Conditional types
타입을 정의할 때 입력에 따라서 다르게 정의할 수 있을까? 당연히 가능하다. 대부분의 프로그래밍 언어처럼 타입스크립트에서도 if문의 역할을 하는 기능이 있다. 바로 Conditional types이다.
T extends U ? X : Y
T타입이 적어도 U타입이라면 X타입 아니라면 Y타입이 된다.
이 개념을 사용한 타입챌린지 문제를 보자.
https://github.com/type-challenges/type-challenges/blob/main/questions/00268-easy-if/README.ko.md
if 타입을 구현하는 문제인데, C타입 참일 때 T, 거짓을 때 F를 반환해야한다. Conditional types을 이용하면 다음과 같이 작성할 수 있다.
type If<C, T, F> = C extends true ? T : F;
그런데 여기까지만 하면 예외처리가 안된다. C로 어떠한 타입도 대입이 될 수 있다.
constraint(제약조건)을 줄 수 있다.
type If<C extends boolean, T, F> = C extends true ? T : F;
이렇게 되면 C 타입에는 적어도 boolean 타입만 대입될 수 있다.
Conditional types를 이용하여 타입 추론도 가능하다. infer 키워드를 이용한다. 타입을 정의하는 시점에서 알 수 없는 타입을 가상의 타입으로 정하고 사용한다.
리턴 타입을 반환해야하는 문제이다. 타입을 정의하는 시점에서는 무슨 타입이 반환될지 모르니 infer를 사용할 수 있다.
type MyReturnType<T extends (...arg : any[]) => any > = T extends (...arg : any[]) => infer R ? R : never;
추가적으로 알아둬야할 유용한 개념이 있다. Distributive Conditinal types, Conditinal types이 유니온 타입을 만나면 분산적으로 동작한다는 개념이다.
Exclude 타입을 구현하는 문제이다.
type MyExclude<T, U> = T extends U ? never : T;
정답은 다음과 같다. T가 유니온 타입이라면 하나씩 U와 비교하고 결과 역시 유니온 타입으로 나올 것이다.
그런데 T가 유니온 타입이라고 제약조건을 걸 필요가 있을까? 전혀 없다. 아니면 아닌거니까!
마지막으로 문제를 하나만 더 살펴보려고 한다.
Lookup 타입을 구현하는 문제이다. 유니온 타입의 특정 속성을 기준으로 조회한다. U가 유니온 타입인걸 알았으니 약간 꼼수로 extends에 왼쪽에 오겠구나 하고 생각할 수도 있다.
type LookUp<U, T> = U extends {type : T} ? U : never;
여러가지 문제를 통해 Conditinal types를 알아보았다.