3

Is it possible to use generics with mapped types in order to map method types?

For example: can you create a mapped type in which you add a first argument of type number to every method?

Pseudo code (won't work)

interface Method<TS extends any[], R> { 
  (...args: TS): R;
}
interface NumberedMethod<TS extends any[], R> { 
  (n: number, ...args: TS): R;
}


type Numbered<T> = {
  // ERROR! Can't use generics here??
  <TS extends any[], R>[K in keyof T]: T[K] extends NumberedMethod<TS, R>? T[K]: T[K] extends Method<TS, R>: NumberedMethod<TS, R>: never;
};

Is there any way in which this is possible?

1 Answer 1

5

If you are trying to extract the generic arguments TS and R from the method, you need to use the infer keyword before a type name in a conditional type (see Type inference in conditional types). This should do what you want:

interface Method<TS extends any[], R> { 
  (...args: TS): R;
}
interface NumberedMethod<TS extends any[], R> { 
  (n: number, ...args: TS): R;
}


type Numbered<T> = {
    [K in keyof T]: T[K] extends Method<infer TS, infer R>? NumberedMethod<TS, R>: T[K];
};

type WithNumber = Numbered<{
    foo : number,
    bar(a: string): void
}> 
// same as 
// type WithNumber = {
//   foo: never;
//   bar: NumberedMethod<[string], void>; // This gets expanded by code completion when accessing the method usually 
// }
Sign up to request clarification or add additional context in comments.

3 Comments

Wow. Conditional types just got a lot more powerful! Thanks for the quick answer.
@nicojs It was there from the beginning just it's a separate feature from vanilla conditional type, but yes infer is mind blowing :)
In your "same as" comment, did you mean foo: number instead of foo: never? (Trying to make sure I understand your black belt type-jitsu is always a good exercise!)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.