raphinesse
raphinesse

Reputation: 21048

Alternatives for a generic type with generic type parameters in TypeScript

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

Answers (1)

raphinesse
raphinesse

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

Related Questions