Home > Back-end >  Building generics on top of other generics
Building generics on top of other generics

Time:10-13

How can one build generics on top of other generics?

Pseudocode illustrating what is required:

type Foo<A> = {
  Bar<B>: { a: A, b: B }
}

// stage one
type FooString = Foo<string> // { Bar<B>: { a: string, b: B } }

// and then later one may do something like this:
type FooBarNumber = FooString['Bar']<number> // { a: string, b: number }
// or this
type FooBarBoolean = FooString['Bar']<boolean> // { a: string, b: boolean }

One workaround is to not do any multistage types, but to define it only once both generics are known:

type FooBar1<A, B> = { a: A, b: B }
// but one then has none DRY code - with `FooString` type 
// having to be repeated multiple times:
type FooBarNumber1 = FooBar1<'FooString Type Repeats', number> 
type FooBarBoolean1 = FooBar1<'FooString Type Repeats', boolean> 

Another solution is to merge the types, but that assumes types can be merged in someway which may not always be easy to achieve and so this is also not an ideal solution

type Foo2<A, R = { a: A }> = R
type FooString2 = Foo2<string>
type Bar2<F extends { a: unknown },B, R = F & { b: B }> = R
type FooBarNumber2 = Bar2<FooString2, number>
type FooBarBoolean2 = Bar2<FooString2, boolean>

code

Is there any other solutions I'm not aware of?

CodePudding user response:

You can partially evaluate types with multiple generic arguments by declaring new generic types with fewer arguments:

type Foo<A, B> = { a: A, b: B };
type FooString<B> = Foo<string, B> //  { a: string, b: B }
type FooBarNumber = FooString<number> // { a: string, b: number }
type FooBarBoolean = FooString<boolean> // { a: string, b: boolean }
  • Related