타입스크립트는 복잡한 타입 정의를 간결하게 만들고, 기존 타입을 재활용하여 새로운 타입을 생성할 수 있도록 다양한 내장 유틸리티 타입과 조건부 타입을 제공합니다. 이를 통해 코드의 재사용성을 높이고 타입 안정성을 강화할 수 있습니다.
유틸리티 타입
타입스크립트 라이브러리에 포함된 주요 유틸리티 타입들을 살펴보겠습니다. 다음 ProductInfo 인터페이스를 예시로 사용하겠습니다.
interface ProductInfo {
id: number;
name: string;
price: number;
description?: string; // 선택적 필드
}
Partial<T>
Partial<T>는 타입 T의 모든 속성을 선택적(optional)으로 만들어 새로운 타입을 생성합니다. 즉, 기존 타입의 모든 속성이 ? (선택적) 수식어를 갖게 됩니다.
type Partial<T> = {
[P in keyof T]?: T[P];
};
// 예시: ProductInfo의 모든 필드를 선택적으로 만듭니다.
type OptionalProduct = Partial<ProductInfo>;
// OptionalProduct 타입은 다음과 같습니다:
// {
// id?: number;
// name?: string;
// price?: number;
// description?: string;
// }
Required<T>
Required<T>는 타입 T의 모든 속성을 필수적(required)으로 만들어 새로운 타입을 생성합니다. 이는 기존 타입의 선택적 속성에서 ? 수식어를 제거하여 필수로 만듭니다.
type Required<T> = {
[P in keyof T]-?: T[P]; // '-' 접두사는 선택적 속성을 필수로 만듭니다.
};
// 예시: ProductInfo의 모든 필드를 필수로 만듭니다.
type MandatoryProduct = Required<ProductInfo>;
// MandatoryProduct 타입은 다음과 같습니다:
// {
// id: number;
// name: string;
// price: number;
// description: string;
// }
Readonly<T>
Readonly<T>는 타입 T의 모든 속성을 읽기 전용(readonly)으로 만들어 새로운 타입을 생성합니다. 이렇게 생성된 타입의 객체는 생성 후 속성 값을 변경할 수 없습니다.
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// 예시: ProductInfo의 모든 필드를 읽기 전용으로 만듭니다.
type ImmutableProduct = Readonly<ProductInfo>;
// ImmutableProduct 타입은 다음과 같습니다:
// {
// readonly id: number;
// readonly name: string;
// readonly price: number;
// readonly description?: string;
// }
Pick<T, K>
Pick<T, K>는 기존 타입 T에서 특정 속성 K만을 선택하여 새로운 타입을 생성합니다. K는 T의 속성 키들의 유니온 타입이어야 합니다.
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
// 예시: ProductInfo에서 'name'과 'price' 속성만 선택합니다.
type ProductSummary = Pick<ProductInfo, "name" | "price">;
// ProductSummary 타입은 다음과 같습니다:
// {
// name: string;
// price: number;
// }
Record<K, T>
Record<K, T>는 K 타입의 속성 키를 가지고, T 타입의 값을 가지는 객체 타입을 생성합니다. K는 문자열, 숫자, 또는 심볼 리터럴의 유니온 타입이 될 수 있습니다.
type Record<K extends keyof any, T> = {
[P in K]: T;
};
// 예시: 요일(문자열 리터럴 유니온)을 키로 가지고, 작업 상태(불리언)를 값으로 가집니다.
type DailyTaskStatus = Record<'Monday' | 'Tuesday' | 'Wednesday', boolean>;
// DailyTaskStatus 타입은 다음과 같습니다:
// {
// Monday: boolean;
// Tuesday: boolean;
// Wednesday: boolean;
// }
조건부 타입
조건부 타입은 특정 타입이 다른 타입에 할당 가능한지 여부에 따라 다른 타입을 선택하는 메커니즘을 제공합니다. 이는 유니온 타입에서 특정 멤버를 필터링하거나 함수의 반환 타입, 클래스의 인스턴스 타입을 추론하는 데 유용하게 사용됩니다.
Exclude<T, U>
Exclude<T, U>는 타입 T에서 타입 U에 할당 가능한 모든 타입을 제외한 새로운 타입을 생성합니다.
type NumericOrString = Exclude<number | string | boolean, boolean>;
// NumericOrString 타입은 number | string 입니다.
type ValidIdTypes = Exclude<string | number | symbol, symbol>;
// ValidIdTypes 타입은 string | number 입니다.
Extract<T, U>
Extract<T, U>는 타입 T에서 타입 U에 할당 가능한 모든 타입만을 추출하여 새로운 타입을 생성합니다.
type OnlyFunctions = Extract<string | number | (() => void), Function>;
// OnlyFunctions 타입은 (() => void) 입니다.
type AllowedUserRoles = Extract<'admin' | 'user' | 'guest', 'admin' | 'user'>;
// AllowedUserRoles 타입은 'admin' | 'user' 입니다.
NonNullable<T>
NonNullable<T>는 타입 T에서 null과 undefined를 제외한 새로운 타입을 생성합니다.
type CleanValue = NonNullable<string | number | null | undefined>;
// CleanValue 타입은 string | number 입니다.
type MessageContent = NonNullable<string | null>;
// MessageContent 타입은 string 입니다.
ReturnType<T>
ReturnType<T>는 함수 타입 T의 반환 타입을 추론하여 새로운 타입을 생성합니다.
// 예시 함수 정의
function processData(input: string, count: number) {
return {
processedInput: input.toUpperCase(),
finalCount: count * 2,
timestamp: Date.now()
};
}
// processData 함수의 반환 타입을 추론합니다.
type ProcessResult = ReturnType<typeof processData>;
// ProcessResult 타입은 다음과 같습니다:
// {
// processedInput: string;
// finalCount: number;
// timestamp: number;
// }
// 화살표 함수의 반환 타입 추론
const getMessage = (name: string) => `Hello, ${name}!`;
type MessageType = ReturnType<typeof getMessage>; // string
InstanceType<T>
InstanceType<T>는 생성자 함수 타입 T의 인스턴스 타입을 추론하여 새로운 타입을 생성합니다.
// 예시 클래스 정의
class Configuration {
private settings: Record<string, any>;
constructor(initialSettings: Record<string, any>) {
this.settings = initialSettings;
}
getSetting(key: string) {
return this.settings[key];
}
}
// Configuration 클래스의 인스턴스 타입을 추론합니다.
type ConfigInstance = InstanceType<typeof Configuration>;
// ConfigInstance 타입은 Configuration 클래스의 인스턴스입니다.
// 즉, ConfigInstance는 { settings: Record; getSetting(key: string): any; } 입니다.