조건부 타입 (Conditional Types)
조건부 타입은 T extends U ? X : Y 형태로 사용되며, 타입 T가 U의 서브타입이면 X, 아니면 Y를 반환하는 타입입니다.
이는 JavaScript의 삼항 연산자(? : )와 유사한 역할을 하며, 제네릭과 함께 사용하여 동적인 타입 변환이 가능합니다.
1️⃣ 장점
- 유연한 타입 변환: 특정 조건에 따라 타입을 동적으로 결정할 수 있음
- 코드 재사용성 증가: 제네릭과 결합하여 다양한 상황에서 활용 가능
- 더 정교한 타입 검사: 복잡한 로직을 간결하게 표현 가능
2️⃣ 예시
🔹 기본적인 조건부 타입
조건부 타입은 T extends U ? X : Y와 같은 형태로 작성합니다. 이를 통해 T가 U의 서브타입이면 X, 아니면 Y를 반환합니다.
type IsString<T> = T extends string ? "문자열" : "문자열 아님"
type A = IsString<string>; // 문자열
type B = IsString<number>; // 문자열 아님
🔹 다중 조건 처리
T가 여러 조건 중 하나에 해당하는지 확인하고, 해당하는 타입을 반환하는 예시입니다.
type GetType<T> =
T extends number ? "숫자" :
T extends string ? "문자열" :
"기타";
type X = GetType<number>; // "숫자"
type Y = GetType<string>; // "문자열"
type Z = GetType<boolean>; // "기타"
🔹 배열 여부 판별
type IsArray<T> = T extends any[] ? "배열" : "아님";
type A = IsArray<number[]>; // "배열"
type B = IsArray<string>; // "아님"
3️⃣ 타입 추론 infer
조건부 타입 내에서 infer를 사용하면 타입 추론을 자동으로 할 수 있습니다.
즉, T가 특정 타입일 경우 해당 타입을 추론하여 그 타입을 활용할 수 있습니다.
🔹 infer 사용 예시
T extends Promise<infer R>은 Promise 내부에 있는 타입 R을 추론합니다.
type ResolveType<T> = T extends Promise<infer R> ? R : T;
type A = ResolveType<Promise<string>>; // string
type B = ResolveType<Promise<number>>; // number
type C = ResolveType<Promise<boolean>>; // boolean
type D = ResolveType<string>; // string (그대로 반환)
4️⃣ 연습 문제
🔹 문제 1 : number 타입인지 판별하기
// ✅ 주어진 타입이 숫자 타입(number)이면 "숫자"를, 아니면 "다른 타입"을 반환하는 타입을 작성하세요.
type IsNumber<T> = ???
type A = IsNumber<number>; // "숫자"
type B = IsNumber<string>; // "다른 타입"
type C = IsNumber<boolean>; // "다른 타입"
정답 보기 🔍
type IsNumber= T extends number ? "숫자" : "다른 타입"
✔️ 타입 T가 number라면 "숫자"를 아니면 "다른 타입"을 반환
🔹 문제 2 : 객체 타입에서 선택적 프로퍼티(?)만 추출하기
// ✅ 객체 타입 T에서 선택적 프로퍼티만 추출하는 타입을 구현하세요. 선택적 프로퍼티는 undefined 값을 가질 수 있는 프로퍼티입니다.
type ExtractOptional<T> = ???
type Obj = {
name: string;
age?: number;
isActive?: boolean;
};
type A = ExtractOptional<Obj>; // { age?: number; isActive?: boolean; }
type B = ExtractOptional<{ name: string; isActive: boolean }>; // {}
정답 보기 🔍
type ExtractOptional= { [K in keyof T as undefined extends T[K] ? K : never]: T[K]; };
✔️ K in keyof T → T의 모든 키를 순회
✔️ as undefined extends T[K] ? K : never → 선택적 속성만 남김
✔️ 필터링된 키로 새로운 객체 타입을 생성
🔹 문제 3 : 함수 타입에서 반환 타입 추출하기
// ✅ 주어진 함수 타입 `T`에서 반환 타입을 추출하는 타입 `ReturnTypeOf`를 작성하세요.
// 예시: `T`가 `(x: string) => number`라면 반환 타입은 `number`입니다.
type ReturnTypeOf<T> = ???
type A = ReturnTypeOf<(x: string) => number>; // number
type B = ReturnTypeOf<(a: boolean) => string>; // string
type C = ReturnTypeOf<(x: string, y: number) => void>; // void
type D = ReturnTypeOf<() => boolean>; // boolean
정답 보기 🔍
type ReturnTypeOf= T extends (...args: any[]) => infer R ? R : never;
✔️ 파라미터는 any[]로 받아 모든 인자 타입을 허용
✔️ T가 함수 타입이라면 infer R로 반환값의 타입을 추론
✔️ 함수 타입이 아니라면 never를 반환