T extends unknown ? Generic<T> : never
의 의미
Mapping Over Union Types
When we use a conditional type on a union, we apply a transformation to each of its elements. Conditional types have two branches, but if we use a condition that always passes, we can transform all elements in the same way:
type MapOverUnion<U> = U extends unknown
/* 👆 👆
The expression This condition
distributes here. always passes.
*/
? Transform<U>
/* 👆
`Transform` is called with every member, one by one.
*/
: never;
Since all TypeScript types are assignable to unknown
, U extends unknown
always passes, so all members of U
will go through the same code branch.
Let’s say we have a Duplicate
generic that puts a type twice in a tuple:
type Duplicate<T> = [T, T];
If we call Duplicate
with 1 | 2 | 3
we get a tuple containing this union twice:
type T1 = Duplicate<1 | 2 | 3>;
// => [1 | 2 | 3, 1 | 2 | 3]
But if we use U extends unknown
beforehand, we get a union of tuples instead:
type DistributeDuplicate<U> = U extends unknown ? [U, U] : never;
type T2 = DistributeDuplicate<1 | 2 | 3>;
// => [1, 1] | [2, 2] | [3, 3]
T1
and T2
are different because T1
can contain mixed arrays, but T2
cannot:
const tuple1: T1 = [1, 2]; // ✅ type-checks!
const tuple2: T2 = [1, 2]; // ❌ does not type-check.
We essentially just mapped Duplicate
over our union type!
[1, 2, 3].map((x) => [x, x]);
// => [[1, 1], [2, 2], [3, 3]]