조건부 타입
조건부 타입 소개
/**
* 조건부 타입
*/
// 앞에 있는 타입이 뒤에 있는 타입의 서브 타입인지 확인해서 맞다면 ? 뒤, 틀리다면 : 뒤 타입 할당
type A = number extends string ? string : number;
type ObjA = {
a: number;
};
type ObjB = {
a: number;
b: number;
};
type B = ObjB extends ObjA ? number : string;
/**
* 제네릭과 조건부 타입
*/
type StringNumberSwitch<T> = T extends number ? string : number;
let varA: StringNumberSwitch<number>;
let varB: StringNumberSwitch<string>;
// 오버로드 시그니쳐
function removeSpaces<T>(text: T): T extends string ? string : undefined;
function removeSpaces(text: any) {
if (typeof text === "string") {
return text.replaceAll(" ", "");
} else {
return undefined as any;
}
}
let result = removeSpaces("hi i'm rachel pink");
result.toLowerCase();
분산적인 조건부 타입
/**
* 분산적인 조건부 타입
*/
// 분산적으로 작동하고 싶지 않다면 extends 양 옆에 []
// type StringNumberSwitch<T> = [T] extends [number] ? string : number;
// c, d -> number
type StringNumberSwitch<T> = T extends number ? string : number;
let a: StringNumberSwitch<number>;
let b: StringNumberSwitch<string>;
let c: StringNumberSwitch<number | string>;
let d: StringNumberSwitch<boolean | number | string>;
// 1단계
// StringNumberSwitch<boolean>
// StringNumberSwitch<number>
// StringNumberSwitch<string>
// 분리된 후 유니온으로 묶인다
// 2단계
// number |
// string |
// number
// 결과
// number | string
/**
* 실용적인 예제
*/
// T와 U가 같을 때 never를 반환하게 해서 아예 타입을 없애고,
// T와 U가 같을 때 T 타입 반환
type Exclude<T, U> = T extends U ? never : T;
type A = Exclude<number | string | boolean, string>;
// 1단계
// Exclude<number, string> |
// Exclude<string, string> |
// Exclude<boolean, string>
// 2단계
// number |
// never |
// boolean
// 결과
// number | never | boolean
// -> number | boolean
// 반대 예시
type Extract<T, U> = T extends U ? T : never;
type B = Extract<number | string | boolean, string>;
// 1단계
// Extract<number, string>
// Extract<string, string>
// Extract<boolean, string>
// 2단계
// never |
// string |
// never
// 결과
// string
infer - 조건부 타입 내에서 타입 추론하기
/**
* infer - 조건부 타입 내에서 타입 추론하기
*/
type FuncA = () => string;
type FuncB = () => number;
type ReturnType<T> = T extends () => infer R ? R : never;
type A = ReturnType<FuncA>; // string
type B = ReturnType<FuncB>; // number
type C = ReturnType<number>; // R을 추론할 수 없어 거짓 -> never
/**
* 예제
*/
type PromiseUnpack<T> = T extends Promise<infer R> ? R : never;
// 1. T는 프로미스 타입이어야 한다.
// 2. 프로미스 타입의 결괏값 타입을 반환해야 한다.
type PromiseA = PromiseUnpack<Promise<number>>; // number
type PromiseB = PromiseUnpack<Promise<string>>; // string
[참고]
한 입 크기로 잘라먹는 타입스크립트
- Section 9. 조건부 타입 강의를 듣고 정리한 내용입니다.