Suggestion
🔍 Search Terms
- mapped type
- type mapping
- generics
- generic function
- unknown
✅ Viability Checklist
My suggestion meets these guidelines:
⭐ Suggestion
Performing type mapping on a generic type should result in a new generic type with that mapping applied, rather than a concrete type with unknown in place of generics.
📃 Motivating Example
Consider the following utility type Async<T>. It takes an arbitrary function signature and returns the signature of an equivalent asynchronous function.
typeAsync<Textends(...args: any)=>any>=Textends(...args: infer Args)=> infer Result
? (...args: Args)=>Promise<Result>
: never;typeSimpleFunction=(arg: number)=>string;typeAsyncSimpleFunction=Async<SimpleFunction>;// result: (arg: number) => Promise<string> ✅
Now let's give it a generic function:
typeGenericFunction1=<T>(arg: T)=>string;typeAsyncGenericFunction1=Async<GenericFunction1>;// expected: <T>(arg: T) => Promise<string>// actual: (arg: unknown) => Promise<string> ⛔️typeGenericFunction2=<T>(arg: number)=>T;typeAsyncGenericFunction2=Async<GenericFunction2>;// expected: <T>(arg: number) => Promise<T>// actual: (arg: number) => Promise<unknown> ⛔️
As this example shows, we cannot use the helper type Async<T> with a generic function signature. If we try, we get a non-generic function signature with unknown wherever a generic argument was used.
💻 Use Cases
We maintain a plugin system. Plugins are developed against a carefully designed API. For every type in the plugin API, there is a corresponding internal type. Plugin values and internal values are identical at runtime, but their types differ. For instance, the same concept may be represented by a class internally, but by a branded interface towards the plugins.
To convert between an internal type and its corresponding plugin type, we use a recursive mapped type. This words great, unless the value is (or contains) a generic function.
Suggestion
🔍 Search Terms
✅ Viability Checklist
My suggestion meets these guidelines:
⭐ Suggestion
Performing type mapping on a generic type should result in a new generic type with that mapping applied, rather than a concrete type with
unknownin place of generics.📃 Motivating Example
Consider the following utility type
Async<T>. It takes an arbitrary function signature and returns the signature of an equivalent asynchronous function.Now let's give it a generic function:
As this example shows, we cannot use the helper type
Async<T>with a generic function signature. If we try, we get a non-generic function signature withunknownwherever a generic argument was used.💻 Use Cases
We maintain a plugin system. Plugins are developed against a carefully designed API. For every type in the plugin API, there is a corresponding internal type. Plugin values and internal values are identical at runtime, but their types differ. For instance, the same concept may be represented by a class internally, but by a branded interface towards the plugins.
To convert between an internal type and its corresponding plugin type, we use a recursive mapped type. This words great, unless the value is (or contains) a generic function.