[TypeScript] 조건부 타입

Jeris·2023년 6월 9일
0

TypeScript

목록 보기
9/11

조건부 타입

조건부 타입(conditional type)이란 extends와 삼항 연산자를 이용해 조건에 따라 각각 다른 타입을 정의하도록 돕는 문법입니다.

type A = number extends string ? string : number; // A = number

type ObjA = {
  a: number
};

type ObjB = {
  a: number;
  b: number;
};

type B = ObjB extends ObjA ? number : string; // B = number

제네릭 조건부 타입

type StringNumberSwitch<T> = T extends number ? string : number;

let varA: StringNumberSwitch<number>; // varA: string
let varB: stringNumberSwitch<string>; // varB: number

함수 오버로딩

function removeSpace<T>(text: T): T extends string ? string : undefined;
function removeSpace(text: any) {
// any 타입 별칭이 컴파일 에러를 감지해주지 못하므로 위의 overload signature를 활용해야 합니다.
  if (typeof text === "string") {
    return text.replaceAll(" ", "");
  } else {
    return undefined;
  }
}

let result = removeSpaces("hi im winterlood");
result.toUpperCase();

분산적인 조건부 타입

분산적인 조건부 타입(distributive conditional types)이란 조건부 타입(conditional types)이 유니온 타입(union types)에 적용될 때 각각의 조건부 타입이 유니온 타입의 각각의 멤버에 분산(distribute)되는 현상을 의미합니다.

// 조건부 타입
type StringNumberSwitch<T> = T extends number ? string : number;

let a: StringNumberSwitch<number>; // a: string
let b: StringNumberSwitch<string>; // b: number

// 분산적인 조건부 타입
let c: StringNumberSwitch<number | string>; // c: string | number
// StringNumberSwitch<number> |
// StringNumberSwitch<string>

let d: StringNumberSwitch<boolean | number | string>; // d: number | string
// 1 단계
// StringNumberSwitch<boolean> |
// StringNumberSwitch<number> |
// StringNumberSwitch<string>

// 2 단계
// number |
// string |
// number

type Exclude<T, U> = T extends U ? never : T;

type A = Exclude<number | string | boolean, string>; // A = number | boolean
// 1 단계
// Exclude<number, string> |
// Exclude<string, string> |
// Exclude<boolean, string>

// 2 단계
// number |
// never |
// boolean

type Extract<T, U> = T extends U ? T : never;

type B = Extract<number | string | boolean, string>; // B = string
// 1 단계
// Extract<number, string>
// Extract<string, string> |
// Extract<boolean, string>

// 2 단계
// never |
// string |
// never

// 분산적인 조건부 타입을 방지하려면 튜플 타입을 사용하면 됩니다.
type StringNumberSwitch<T> = [T] extends [number] ? string : number;

infer

infer 키워드는 타입스크립트의 조건부 타입에서 사용되며, 해당 조건이 참이 될 때 추론할 수 있는 타입을 나타냅니다.

type ReturnType<T> = T extends () => infer R ? R : never;
/**
* 조건식 T extends () => infer R에서 infer R은
* 이 조건식을 참이 되도록 만들 수 있는 최적의 R 타입을 추론하라는 의미입니다.
*/

type FuncA = () => string;
type FuncB = () => number;

type A = ReturnType<FuncA>; // A = string
type B = ReturnType<FuncB>; // B = number
type C = ReturnType<number>; // C = never

infer로 프로미스 결과 타입을 추출하기

type PromiseUnpack<T> = T extends Promise<infer R> ? R : never;

type PromiseA = PromiseUnpack<Promise<number>>; // PromiseA = number
type PromiseB = PromiseUnpack<Promise<string>>; // PromiseB = string

Reference

profile
job's done

0개의 댓글