TL;DR:
type NonDistributive<T extends string> = { kind: T };
type Distributive<T extends string> = { [K in T]: { kind: K } }[T];
type A = NonDistributive<'x' | 'y'>
// ^? type A = { kind: 'x' | 'y' }
type B = Distributive<'x' | 'y'>
// ^? type B = { kind: 'x' } | { kind: 'y' }
Given the following
Token uniontype Token = 'x' | 'y' | 'z'
Let's say you want to create a new shape from
Token that's something like this:type Discriminated = { kind: 'x' } | { kind: 'y' } | { kind: 'z' }
And you try the most obvious way
type Map<T extends Token> = { kind: T };
It won't work because it won't "distribute" Token members correctly.
It will create a single
{ kind: T } with every T member:type T = Map<Token>;
// ^? type T = { kind: 'x' | 'y' | 'z' }
We will need to use distribute the union in a way each member is treated individually, like
K in T:type Map<T extends Token> = { [K in T]: { kind: K } }[T]
type T = Map<Token>
// ^? type T = { kind: 'x' } | { kind: 'y' } | { kind: 'z' }
Using conditional type (a single ternary T extends any) also does the distributive because the condition checks each member individually:
type Map<T extends Union> = T extends any ? { kind: T } : never;
type T = Map<Token>;
// ^? type T = { kind: 'x' } | { kind: 'y' } | { kind: 'z' }
In other words:
type Map<T extends Union> = { kind: T };
// ^ this T is a whole union 'x' | 'y' | 'z'
type Map<T extends Union> = T extends any ? { kind: T } : never;
// ^ this T represents a single union member eg 'y'
type Map<T extends Union> = { [P in T]: { kind: P } }[T]
// ^ this P is a single union member of T eg 'y'