Reputation: 21048
Suppose I have two types for generic functions that only differ in their return type. One has return type T
, the other T[]
:
type F1 = <T>(t: T) => T
type F2 = <T>(t: T) => T[]
I wondered how those two types could be consolidated into one generic type. The way I imagined doing that was to have that new generic type accept another generic type as a parameter (like C++'s template template parameters):
// Caution, Fantasy-TypeScript ahead!
// Accepts generic type R as parameter
// to transform return type of generic function
type F<R> = <T>(t: T) => R<T>
// define F1 and F2 in terms of F
type Id<T> = T
type F1 = F<Id>
type F2 = F<Array>
However, generic generic parameters are not supported yet (March 2021). See TypeScript Issue and a related SO question for more information.
What would be an alternative in TypeScript?
Upvotes: 2
Views: 794
Reputation: 21048
A simple approach would be to use Conditional Types:
type F<R> = <T>(t: T) => R extends void[] ? T[] : T
type F1 = F<void> // <T>(t: T) => T
type F2 = F<void[]> // <T>(t: T) => T[]
A more flexible implementation can be achieved using Indexed Access Types:
type R<T> = { Id: T, Array: T[] }
type F<K extends keyof R<any>> = <T>(t: T) => R<T>[K]
type F1 = F<'Id'> // <T>(t: T) => T
type F2 = F<'Array'> // <T>(t: T) => T[]
See my answer to a similar question for a more involved example of this technique.
Upvotes: 4