반응형
조건부 타입
기본 문법
type IsStringType<T> = T extends string ? 'yes' : 'no';
type T1 = IsStringType<string>
type T2 = IsStringType<number>
- T에들어온 타입이 string이면 yes, number 이면 no가 되는 조건부 문법을 사용하는 기능이다.
- 자바스크립트의 삼항 연산자 문법을 사용하여 값을 다루는 것처럼 보이지만 타입스크립트에서의 위의 코드는 값이 아닌 타입에 대한 것이라고 봐야한다.
union과 조건부 타입
type IsStringType<T> = T extends string ? 'yes' : 'no';
type T1 = IsStringType<string | number>
type T2 = IsStringType<string> | IsStringType<number> ;
type Array2<T> = Array<T>;
type T3 = Array2<string | number>;
- T1의 union의 <string | number>는 사실 T로 들어가면 T extends string에서 할당이 안되어 'no'가 될것 같았지만 조건부 타입에서는 string과 number에 따라 'yes' 'no' 둘 중 하나가 될 수 있게 되었다. 특별한 예외이다.
- 즉 T1은 T2와 같은 형태를 가지고 있다고 보면된다. 둘의 결과는 똑같은 결과를 가진다.
- 하지만 조건부 랜더링 없이 재네릭에서 union타입이 입력되면 T3는 type Array2<T> = Array<T> 로 인하여 string[] | number[]가 되는 것이 아니라 string 또는 number의 배열이 된다는 것이다.
Exclude와 Extract 타입
type T1 = number | string | never;
type Exclude<T, U> = T extends U ? never : T;
type T2 = Exclude<1 | 3 | 5 | 7, 1 | 5 | 9>;
type T3 = Exclude<string | number | (() => void), Function>;
type Extract<T, U> = T extends U ? T : never;
type T4 = Extract<1 | 3 | 5 | 7, 1 | 5 | 9>;
- Exclude 타입을 보면 T가 U에 할당 가능할때 true을 반환하도록 되었다. 즉 T2에서 U인 1 | 5 | 9에 할당 가능한 T의 1과 5가 true로 반환되어 never로 인하여 삭제되고 false을 반환한 3과 7은 T에 삽입되어 T2의 타입은 3과 7이 된다.
- 마찬가지로 T3 또한 함수Function로 할당되지 못하는 타입 string과 number 만이 T로 삽입되고 함수인 (() => void)는 never로 인하여 제거된다.
- 반대로 Extract 타입은 할당 가능한 1, 5이 T4의 타입이 된다.
Returntype
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type T1 = ReturnType<() => string>;
function f1(s: string): number {
return s.length;
}
type T2 = ReturnType<typeof f1>;
- Returntype은 T가 함수일때 T함수 반환 타입을 뽑아주는 역할을 한다. 타입스크립트에 내장된 기능이며 type문 생략 가능하다.
- (...arg: any[]) => infer R ? R: any가 그 역할을 해준다. T가 함수에 할당 가능한 것이면 R을 사용하겠다라는 의미이다.
- 여기서 R은 함수의 반환타입을 의미한다. infer라는 키워드 덕분에 함수의 반환 타입을 알 수 있고 R이라는 변수에 반환 타입을 담을 수 있다는 것도 중요하다. T1에는 R에 string이라는 반환 타입이 담기게 되었다.
- T2는 재네릭에서 값이 아닌 타입만 가져올 수 있기 때문에 typeof라는 키워드를 사용하여 실제 함수인 f1을 가져와 타입을 추출해내어 Return 타입의 재네릭에 담가주었다.
- f1은 number을 반환하기 때문에 T2는 number의 타입을 가지게 된다.
infer 활용
type Unpacked<T> = T extends (infer U)[]
? U
: T extends (...args: any[]) => infer U
? U
: T extends Promise<infer U>
? U
: T;
type T0 = Unpacked<string>; //자기 자신 string을 타입으로 반환
type T1 = Unpacked<string[]>; //배열이기에 첫번째 조건부에서 U에 string 타입 반환
type T2 = Unpacked<() => string>; // 함수이기에 두번째 조건부에서 U에 반환 string 타입 반환
type T3 = Unpacked<Promise<string>>;// Promise 이기에 세번째 조건에서 U에 string 타입 반환
type T4 = Unpacked<Promise<string>[]>;// []이 있기에 첫번째 조건부에서 걸려 Promise가 타입으로 반환
type T5 = Unpacked<Unpacked<Promise<string>[]>>;
//두번 Unpacked을 호출하였기에 처음에는 []로 인하여 첫번째 조건부에 걸려 Promise가 반환되지만
//한번 더 Unpacked을 호출한 영향으로 세번째 조건부에 걸려 Promise의 string이 U에 타입으로 반환된다.
타입 조건부 활용 - 유틸리티 함수
type StringPropertName<T> = {
[K in keyof T]: T[K] extends string ? K : never;
}[keyof T];
interface Person {
name: string;
age: number;
nation: string;
}
type T1 = StringPropertName<Person>; //T1의 타입은 name과 nation이다.
type StringProperties<T> = Pick<T, StringPropertName<T>>;
type T2 = StringProperties<Person>;
- StringPropertName 타입은 값이 문자열인 속성 이름을 추출하는 유틸리티 함수이다.
- 맵드 타입을 이용하여 받은 T 인터페이스는 in key of을 통해 자신의 키 이름을 T[K]의 K에 넣어 조건부 타입을 이용하여 string인 문자열 속성 이름이 true로 반환하게 하도록 하였다. 나머지 false 반환 값들은 never로 인해 제거된다.
- 또 StringProperties 타입은 Pick 키워드를 사용하여 T에 들어온 인터페이스를 이용하여 T의 인터페이스 중 StringPropertName<T>의 타입만을 T 인터페이스에서 선택하여 T2의 타입 값들로 지정해준다.
- T2는 const T2 ={ name: string; nation: string; }이 되었다.
Omit 타입
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'>;
- Omit 또한 타입스크립트의 내장된 기능이며 type문을 생략 가능하다.
- Pick과 Exclude 키워드를 조합하여 기능을 실행한다. U extends T에서 U에는 T에 할당 가능한 속성만이 들어갈 수 있으며 Exclude에서 전체 T의 속성에서 U의 타입 속성을 지우고, Pick을 이용하여 U 타입들을 제거한 T의 타입 속성 값만을 T에서 골라내는 원리이다.
- T1은 const T1 = { name: string; }라고 타입이 지정되었다.
Overwrite
type Overwrite<T, U> = { [P in Exclude<keyof T, keyof U]: T[P] } & U;
interface Person {
name: string;
age: number;
}
type T1 = Overwrite<Person, { nation: string; age: string; };
const p: T1 = {
name: 'jinseok',
age: 26, //타입 오류. age의 타입은 T1에서 string이다.
nation: 'korea'
}
- 타입스크립트에 내장된 객체는 아니어서 type문 생략은 가능하지는 않다.
- 중복되는 타입을 하나로 합쳐주고 중복되지 않는 타입 또한 더해주는 기능을 담담하고 있다.
- Overwrite로 T와 U을 받아 일단 Exclude을 통해 U의 타입들을 T 타입에서 제거해주고 곧바로 맵드 타입에서 T[P]문법을 이용하여 Exclude에서 걸러진 T의 타입 값들을 넣어주는 과정을 통해 중복된 타입 값들을 처리한다.
- 그리고 마지막에 U와 &을 이용하여 교집합 시켜주어 중복되지 않은 타입을 더해준다.
반응형
'프로그래밍 개발 > Typescript' 카테고리의 다른 글
Typescript 타입 가드 (0) | 2021.05.11 |
---|---|
Typescript 타입 추론 (0) | 2021.05.11 |
Typescript 맵드 타입(mapped type) (0) | 2021.05.10 |
Typescript 재네릭 (0) | 2021.05.07 |
Typescript 타입 호환성 (0) | 2021.05.07 |
댓글