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]]