타입챌린지에서 Exclude를 구현하던 도중 come across 하게된 개념이다.
우선 Exclude를 구현해보자
type MyExclude<T,U> = T extends U ? never : T
type Result = MyExclude<'a'|'b'|'c','b'> // 'a' | 'c'
어떻게 이렇게 되는 걸까?? Distributive conditional types에 대한 타입스크립트 공문을 보자.
Conditional types in which the checked type is a naked type parameter are called "distributive conditional types."
Distributive conditional types are automatically distributed over union types during instantiation.
For example, an instantiation of T extends U ? X : Y with the type argument A | B | C for T is resolved as (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y).
타입의 조건을 파악하는 로직에서 넘어온 타입이 naked type일 경우 distributive conditional types라고 한다. 여기서 naked type이란 어떠한 것으로도 감싸여있지 않은 타입을 말한다.
['a']
처럼 튜플로 감싸진것은 naked가 아니다 'a'
가 naked이다.
이때, 각각의 타입에 조건이 적용된다. 그리고 각각의 조건의 리턴값이 union되어 리턴된다.
그래서 MyExclude를 다시 파헤쳐보자
MyExclude<'a'|'b'|'c','b'>
/*
'a' extends 'b' ? never : 'a' |
'b' extends 'b' ? never : 'b' |
'c' extends 'b' ? never : 'c'
==> 'a' | 'c'
*/
이렇게 되는 것이다. naked가 아니면 그냥 하나의 조건문으로 해석하면 된다.
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
type StrOrNumArr = ToArrayNonDist<string | number>;
// Result: (string | number)[]
출처:https://www.linkedin.com/pulse/typescript-distributive-conditional-types-heydar-murad/