본문 바로가기

TypeScript

TypeScript Mapped Types 완벽 가이드 - 타입 변환 마스터하기

TYPESCRIPT Guide Mapped Types 완벽 가이드 { type Mapped <T> = { [K in keyof T]: T[K] } }

TypeScript Mapped Types 완벽 가이드 - 타입 변환 마스터하기

TypeScript로 대규모 프로젝트를 진행하다 보면 기존 타입을 변형해야 하는 상황이 자주 발생해요. Mapped Types는 이런 타입 변환을 자동화해주는 강력한 도구로, Partial이나 Readonly 같은 유틸리티 타입의 핵심 원리이기도 합니다.

Mapped Types란 무엇인가?

Mapped Types는 기존 타입의 각 프로퍼티를 순회하며 새로운 타입을 생성하는 문법이에요. in 키워드를 사용해 타입의 키를 반복하고, 각 프로퍼티에 변환 로직을 적용할 수 있죠.

기본 문법은 다음과 같아요:

type MappedType<T> = {
  [P in keyof T]: T[P];
};

여기서 keyof T는 타입 T의 모든 키를 유니온 타입으로 추출하고, P in keyof T는 각 키를 순회하며 T[P]로 해당 키의 타입을 참조합니다.

실전 활용 - 선택적 프로퍼티 만들기

가장 많이 사용하는 패턴은 모든 프로퍼티를 선택적으로 만드는 거예요. TypeScript의 Partial<T>도 이 원리로 구현되어 있습니다.

type MyPartial<T> = {
  [P in keyof T]?: T[P];
};

interface User {
  id: number;
  name: string;
  email: string;
}

type PartialUser = MyPartial<User>;
// { id?: number; name?: string; email?: string; }

API 응답 데이터 처리나 폼 업데이트 로직에서 특히 유용해요. 전체 객체가 아닌 일부 필드만 업데이트할 때 타입 안정성을 유지할 수 있거든요.

조건부 타입과 결합하기

Mapped Types의 진가는 조건부 타입과 결합할 때 드러나요. 특정 조건에 맞는 프로퍼티만 선택적으로 변환할 수 있습니다.

type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

type OnlyStrings<T> = {
  [P in keyof T as T[P] extends string ? P : never]: T[P];
};

as 절을 사용하면 키 자체를 필터링하거나 변환할 수도 있어요. 이를 활용하면 특정 타입의 프로퍼티만 추출하거나, getter/setter 패턴을 자동 생성하는 등 고급 타입 변환이 가능합니다.

템플릿 리터럴과 함께 사용하기

TypeScript 4.1부터 템플릿 리터럴 타입을 Mapped Types와 결합할 수 있게 되었어요. 이를 활용하면 프로퍼티명을 동적으로 변환할 수 있습니다.

type Getters<T> = {
  [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

interface Product {
  name: string;
  price: number;
}

type ProductGetters = Getters<Product>;
// { getName: () => string; getPrice: () => number; }

이 패턴은 Vue나 MobX 같은 프레임워크에서 반응형 객체를 타이핑할 때 특히 강력해요.

주의사항

Mapped Types를 과도하게 중첩하면 컴파일 속도가 느려지고 타입 에러 메시지가 복잡해질 수 있어요. 가독성을 위해 복잡한 타입 변환은 여러 단계로 나누고, 중간 타입에 명확한 이름을 붙이는 게 좋습니다. 또한 keyof 연산은 인덱스 시그니처를 포함하므로, 예상치 못한 string | number | symbol 타입이 나올 수 있다는 점도 기억하세요.

결론

Mapped Types는 TypeScript의 타입 시스템을 진정으로 활용하는 핵심 기능이에요. 처음에는 복잡해 보이지만, 기본 문법만 익히면 반복적인 타입 정의 작업을 크게 줄이고 타입 안정성을 높일 수 있습니다. 실제 프로젝트에서 Partial이나 Pick 같은 유틸리티 타입이 어떻게 구현되었는지 확인하며 학습하면 이해가 훨씬 빨라질 거예요.