조건부 타입은 입력된 제네릭 타입에따라 타입을 결정하는 타입이라고 한다. 예시를 보자.
type IsNumber<T> = T extends number ? "yse" : "no";
type T1 = IsNumber<number>; // type T1 = "yes"
type T2 = IsNumber<string>; // type T2 = "no"
타입 T가 넘버타입에 할당 가능하면 "yes"타입으로 아니면 "no"타입의 타입니다. 자바스크립트에서 삼항연산자와 해석하는 방식은 똑같다고 할 수 있으나 결과값이 타입이라는것에 유념하자.
T1은 "yes" 타입, T2는 "no"타입으로 정리할 수 있다.
다음은 조건부 타입이 적용된 TypeScript의 내장타입에 대해서 알아보자.
Exclude타입은 두 타입중 할당가능한 것에 대해서 never type을 주어 제외시킨 타입이다. 그리고 Extract타입은 그 반대로 둘 중 일치하는 타입을 가져오는 것이다.
//Exclude Type
type Exclude<T, U> = T extends U ? never : T;
type T2 = Exclude<1 | 3 | 5 | 7, 1 | 5 | 9>; // type T2 = 3 | 7
const a1 : T2 = 3
const a2 : T2 = 1 // Error!!
//Extract Type
type Extract<T, U> = T extends U ? T : never;
type T4 = Extract<1 | 3 | 5 | 7, 1 | 5 | 9>; // type T4 = 1 | 5
const b1: T4 = 1;
const b2: T4 = 3; // Error!!
TypeScript내장함수 인 RetrunType은 Return하는 타입을 가져오는 타입방식으로 역시나 조건부 타입으로 구동된다고 한다.
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type T1 = ReturnType<() => string>; // type T1 = string
function f1(s: string): number {
return s.length;
}
type T2 = ReturnType<typeof f1>;// type T2 = number
declare function f2(): { a: number; b: string };
type T3 = ReturnType<typeof f2>; // type T3 = { a: number; b: string }
type T4 = ReturnType<string>; // type T4 = any
여기서 함수의 리턴값을 추론하기 위해서 "infer"라는 키워드가 사용되는데, 없어도 되지 않을까했지만 일종의 extends 키워드와 사용하는 키워드라고 하고, 사용을 안할 경우 에러를 발생할 수 있다고 한다.
[참조 : Why is the infer keyword needed in Typescript?]
역시 내장 타입인 Omit Type은 지난 시간 배웠던 Pick타입과 Exclude타입을 응용한 것이다.
[Pick type에 대한 TypeScript velog]
type Omit<T, U extends keyof T> = Pick<T, Exclude<keyof T, U>>;
interface Person {
name: string;
age: number;
nation: string;
}
type T1 = Omit<Person, "nation" | "age">; // type T1 = { name: string; }
T가 인터페이스라면 U는 T에 속성을 의미하는 것이다. Exclude type으로 보면 입력받은 U중 T 전체속성과 일치하는 것을 빼는 것이고, Pick타입을 통해서 나머지를 결정하는 것이다.
어째 점점 어려워진다. ㅠㅠ