Mapped Types의 기본: 속성 변환
Mapped Types는 주로 인덱스 시그니처 문법을 활용하여 기존 타입의 모든 속성을 대상으로 새로운 타입을 생성합니다.
interface AppState {
loading: number;
error: string;
}
type BooleanState<T> = {
[K in keyof T]: boolean;
};
type AppFlags = BooleanState<AppState>;
const flags: AppFlags = {
loading: false,
error: true,
};
console.log(flags); // 출력: { loading: false, error: true }
매핑 수정자: 속성 제어
`+`와 `-`로 `readonly`나 선택적 속성(`?`)을 추가하거나 제거할 수 있습니다.
readonly 추가
interface Config {
apiKey: string;
timeout: number;
}
type ReadonlyConfig<T> = {
readonly [K in keyof T]: T[K];
};
type LockedConfig = ReadonlyConfig<Config>;
const config: LockedConfig = { apiKey: "xyz", timeout: 5000 };
// config.apiKey = "new"; // 오류: 읽기 전용
console.log(config.apiKey); // 출력: xyz
선택적 속성 제거
interface PartialItem {
name?: string;
price?: number;
}
type RequiredItem<T> = {
[K in keyof T]-?: T[K];
};
type FixedItem = RequiredItem<PartialItem>;
const item: FixedItem = { name: "책", price: 15000 };
// const incomplete: FixedItem = { name: "책" }; // 오류: price 누락
console.log(item); // 출력: { name: "책", price: 15000 }
키 리맵핑: as로 이름 재정의
TypeScript 4.1부터는 as 키워드를 사용하여 기존 키를 새 이름으로 리맵핑할 수 있습니다.
interface Profile {
email: string;
age: number;
}
type SetterProfile<T> = {
[K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};
type ProfileSetters = SetterProfile<Profile>;
const setters: ProfileSetters = {
setEmail: (value) => console.log(`Email set to ${value}`),
setAge: (value) => console.log(`Age set to ${value}`),
};
setters.setEmail("a@b.com"); // 출력: Email set to a@b.com
setters.setAge(25); // 출력: Age set to 25
조건부 타입 결합하기
조건부 타입과 함께 사용하면 특정 속성만 선택하거나 제외할 수 있습니다.
interface Data {
value: string;
meta: { created: string };
}
type WithoutMeta<T> = {
[K in keyof T as Exclude<K, "meta">]: T[K];
};
type SimpleData = WithoutMeta<Data>;
const data: SimpleData = { value: "정보" };
console.log(data.value); // 출력: 정보
유니온 타입과의 조합
Mapped Types는 유니언 타입에서도 분배되어 동작합니다.
type Alert = { type: "info"; message: string } | { type: "error"; code: number };
type AlertHandler<T extends { type: string }> = {
[E in T as E["type"]]: (alert: E) => string;
};
type Handlers = AlertHandler<Alert>;
const alertHandlers: Handlers = {
info: (alert) => `정보: ${alert.message}`,
error: (alert) => `오류 ${alert.code}`,
};
console.log(alertHandlers.info({ type: "info", message: "완료" })); // 출력: 정보: 완료
console.log(alertHandlers.error({ type: "error", code: 404 })); // 출력: 오류 404
'TypeScript' 카테고리의 다른 글
[TypeScript] 클래스: 타입 안정성과 객체 지향의 만남 (0) | 2025.02.27 |
---|---|
[TypeScript] 템플릿 리터럴 타입: 문자열 동적으로 다루기 (0) | 2025.02.27 |
[TypeScript] 조건부 타입: 입력과 출력의 유연함 (0) | 2025.02.27 |
[TypeScript] 인덱스 액세스 타입(Indexed Access Types): 객체 속성 정밀 추출 (0) | 2025.02.27 |
[TypeScript] typeof 타입 연산자 (0) | 2025.02.26 |