분포형 타입(Distributive Types)은 TypeScript에서 조건부 타입(T extends U ? X : Y)을 다룰 때 나타나는 특징입니다. extends의 왼쪽에 있는 타입 변수가 유니온일 때, TypeScript는 조건을 유니온의 각 요소에 분포시킵니다.
예시:
// "Test<A> | Test<B> | Test<C>" type Test<T> = T extends string ? () => string : () => number; type Result = Test<'A' | 'B' | 'C'>;
여기서 Result는 다음과 같이 분포됩니다:
사용 시기 — 범용 API 작성, 유니온에 대한 조작, 예를 들어 필터링 또는 패턴 매칭 등을 위해 사용됩니다.
특징:
[T]로 감싸면 분포가 발생하지 않습니다. 이는 분포를 "비활성화"하는 방법입니다.질문: 타입 T[] extends number[] ? true : false는 분포형인가요?
정답: 아닙니다, 분포는 왼쪽에 배열이나 튜플로 감싸지 않은 타입 변수가 있을 때만 발생합니다. 예를 들어, 조건부 타입 T extends number ? ...는 분포하지만 T[] extends number[] ? ...는 아닙니다.
이야기
프로젝트: React 컴포넌트의 props 유효성 검사 라이브러리. 유니온 prop를 엄격한 인터페이스로 변환하는 타입을 구현하려 했으나 분포를 모르고 타입이 예기치 않게 복잡해졌습니다(유니온 멤버의 속성이 혼합됨). 분포가 발생하지 않도록
[T]로 감싸면서 수정했습니다.
이야기
프로젝트: 모든 이벤트 타입을 하나의 핸들러 함수로 작성하고 있었습니다. 조건부 타입에서 함수가 각 이벤트 타입을 분포를 통해 받을 것이라고 예상했으나 명시적인 사용 없이 잘못된 처리를 하여 인수의 타입에 오류가 발생했습니다(유니온 대신 각 타입에 대한 별도의 호출).
이야기
프로젝트: 사용자 정의 유틸리티 타입(Exclude, Extract 등)을 만들 때 튜플과 배열에 대해서는 분포가 발생하지 않는다는 것을 잊었습니다. 그 결과, Exclude 타입이 배열에서 작동하지 않았습니다(예: 타입
Exclude<["a"|"b"], "b">는 "b"를 제거하지 않았습니다).