In TypeScript I am constructing a type that consists of unions of other types:
type A = B | C | D // ...
I want to want to be sure at compile time that B, C, D, etc. have the shape of a generic template so that the composite is correct. So I need kind of a interface for types or a type for a type.
For example should B "implement" Template:
type Template = { x: string; y: { [key: string]: any } };
type B = {x: "test", y: {test2: number}}
How can I solve this?
CodePudding user response:
EDIT
As @jcalz suggested you can pass a union to a generic type to check if it fits your constraint. Playground.
type Template = { x: string; y: { [key: string]: any } };
type B = { x: "B", y: { test2: number } }
type C = { x: "C", y: { test2: number } }
type D = { x: "C", y: { test2: number } }
type E = { x: 5 }
type Check<U, T extends U> = T
// @ts-expect-error
type AError1 = Check<Template, B | C | E>
// @ts-expect-error
type AError2 = Check<Template, B | C | D | E>
type A = Check<Template, B | C | D>
You can use generics for this, but it gets verbose if you want to have say more then 10 possible types in a union. Playground.
type Template = { x: string; y: { [key: string]: any } };
type B = {x: "B", y: {test2: number}}
type C = {x: "C", y: {test2: number}}
type D = {x: "C", y: {test2: number}}
type E = {x: 5}
type MakeUnion<TBase, T1 extends TBase, T2 extends TBase, T3 extends TBase = never, T4 extends TBase = never, T5 extends TBase = never> = T1 | T2 | T3 | T4 | T5
// @ts-expect-error
type AError1 = MakeUnion<Template, B, C, E>
// @ts-expect-error
type AError2 = MakeUnion<Template, B, C, D, E>
type A = MakeUnion<Template, B, C, D>