"Conditional 타입이 union 에 분배. 알게 되면 몇몇 신비로운 타입 에러가 신비롭지 않아져."
규칙
Conditional 타입의 체크 타입이 벗겨진 (naked) generic 타입 parameter 이고, 그 parameter 가 union 이면, TypeScript 가 conditional 을 union 의 각 멤버에 분배하고 결과를 union. 기호로: T = U1 | U2 에 적용된 T extends X ? A : B 가 (U1 extends X ? A : B) | (U2 extends X ? A : B) 됨.
보통 원하는 거. 가끔 아냐. Escape hatch: parameter 를 bracket 으로 감쌈 — [T] extends [X] — 비교를 single-element tuple test 로 변환하고 분배 비활성화.
분배가 도움될 때
고전 사용: union 에 대한 타입-레벨 mapping. type Wrap<T> = T extends unknown ? { value: T } : never. `string | number` 에 적용하면 분배: Wrap<string> | Wrap<number> = { value: string } | { value: number }. 입력의 각 멤버가 출력에 자기 wrap 된 variant 됨.
같은 패턴: standard library 의 `ExcludeT extends U ? never : T 로 구현 — 분배가 union 에서 특정 멤버 제거하게 만드는 거.
분배가 surprise 일 때
단일 결과 기대하고 union 받음. 또는 분배 기대했는데 안 받음 — 타입 parameter 가 naked 가 아니라서 (다른 모양에 wrap). 두 방향 fix:
- 분배 강제 하려면: conditional 체크 site 에서 parameter naked 유지.
- 분배 막으려면: tuple 로 감쌈 —
[T] extends [X].
Bracket 트릭이 많은 고급 TypeScript 패턴에 나타나. 존재 알면, library 타입 정의에서 항상 발견해.