Posts

[TS] 고급타입(Advanced Types) - Mapped Types

목차13

매핑 타입(Mapped Types)

매핑 타입(Mapped Types)은 기존 타입을 변환하여 새로운 타입을 만들 수 있는 유틸리티 타입 중 하나다. 매핑 타입을 사용하면 기존 타입의 속성 이름, 타입 등을 변경하여 새로운 타입을 만들 수 있다.

매핑 타입의 구조는 아래와 같다.

코드
{ [P in K]: T }

위 구조에서 P는 속성 이름의 타입, K는 P****에 포함될 속성 이름의 타입을 의미하며, T는 속성의 타입을 나타낸다. 

코드
interface Person {
  name: string;
  age: number;
  location: string;
}

위 Person 인터페이스를 매핑 타입을 사용하여 다음과 같이 변환할 수 있다.

코드
type ReadonlyPerson = { readonly [P in keyof Person]: Person[P] };

위 코드에서 keyof Person은 Person 인터페이스의 모든 속성 이름을 union 타입으로 만든다. readonly는 해당 속성이 읽기 전용임을 나타내며, Person[P]는 Person 인터페이스에서 해당 속성의 타입을 가져온다. 따라서 ReadonlyPerson은 다음과 같이 정의된다.

코드
type ReadonlyPerson = {
  readonly name: string;
  readonly age: number;
  readonly location: string;
}

이렇게 매핑 타입을 사용하면 기존 타입을 보다 유연하게 변환할 수 있으며, 이를 통해 코드의 재사용성과 가독성을 높일 수 있다.

또한 다양한 상황에서 유용하게 사용될 수 있다.

모든 속성의 타입을 읽기 전용으로 변경하기

Readonly<T> 타입을 사용하여 기존 타입에서 모든 속성의 타입을 읽기 전용으로 변경하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 모든 속성의 타입을 읽기 전용으로 변경하여 PersonWithReadonlyProps 타입을 만든다.

코드
type PersonWithReadonlyProps = Readonly<Person>;

모든 속성의 타입을 필수로 변경하기

Required<T> 타입을 사용하여 기존 타입에서 모든 속성의 타입을 필수로 변경하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 모든 속성의 타입을 필수로 변경하여 PersonWithRequiredProps 타입을 만든다.

코드
type PersonWithRequiredProps = Required<Person>;

모든 속성의 타입을 선택적으로 변경하기

Partial<T> 타입을 사용하여 기존 타입에서 모든 속성의 타입을 선택적으로 변경하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 모든 속성의 타입을 선택적으로 변경하여 PersonWithPartialProps 타입을 만든다.

코드
type PersonWithPartialProps = Partial<Person>;

모든 속성의 타입을 지정한 타입으로 변경하기

Record<K, T> 타입을 사용하여 모든 속성의 타입을 지정한 타입으로 변경하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 모든 속성의 타입을 number로 변경하여 PersonWithNumberProps 타입을 만든다.

코드
type PersonWithNumberProps = Record<keyof Person, number>;

객체 속성 타입 변경하기

{ [K in keyof T]: U } 문법을 사용하여 객체의 모든 속성의 타입을 일괄적으로 변경할 수 있다.

아래 예시에서는 Person 객체의 모든 속성의 타입을 string으로 변경하여 PersonWithStringProps 타입을 만든다.

코드
type PersonWithStringProps = { [K in keyof Person]: string };

속성 이름을 변경하기

{ [K in keyof T as U]: T[K] } 문법을 사용하여 기존 타입의 속성 이름을 변경하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 age 속성을 years로 변경하여 PersonWithRenamedProps 타입을 만든다.

코드
type PersonWithRenamedProps = { [K in keyof Person as K extends 'age' ? 'years' : K]: Person[K] };

속성 값 변경하기

Pick<T, K> 타입과 조합하여 기존 타입의 일부 속성만 선택하여 해당 속성의 타입을 변경할 수 있다.

아래 예시에서는 Person 타입의 age 속성 타입을 string으로 변경하여 PersonWithStringAge 타입을 만든다.

코드
type PersonWithStringAge = Pick<Person, 'name' | 'location'> & { age: string };

타입에서 특정 속성 제거하기

Omit<T, K> 타입을 사용하여 기존 타입에서 특정 속성을 제거하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 location 속성을 제거하여 PersonWithoutLocation 타입을 만든다.

코드
type PersonWithoutLocation = Omit<Person, 'location'>;

타입에서 선택적 속성 제거하기

Exclude<T, U> 타입을 사용하여 기존 타입에서 U에 해당하는 속성을 제거하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 선택적 속성인 location을 제거하여 PersonWithoutOptional 타입을 만든다.

코드
type PersonWithoutOptional = Pick<Person, Exclude<keyof Person, 'location'>>;

타입에서 특정 속성에 조건 추가하기

Exclude<T, U> 타입과 Pick<T, K> 타입을 조합하여 기존 타입에서 특정 속성의 타입을 변경할 수 있다.

아래 예시에서는 Person 타입에서 age 속성을 선택하여, 해당 속성이 number인 경우 string으로 변경하여 PersonWithStringAge 타입을 만든다.

코드
type PersonWithStringAge = Pick<Person, 'name' | 'location'> & { age: Exclude<Person['age'], number> } & { age?: string };

타입에서 undefined 속성 제거하기

NonNullable<T> 타입을 사용하여 기존 타입에서 undefined 값을 가질 수 있는 속성을 제거하여 새로운 타입을 만들 수 있다.

아래 예시에서는 Person 타입에서 age 속성이 undefined 값을 가질 수 있는 경우 제거하여 PersonWithoutUndefined 타입을 만든다.

코드
type PersonWithoutUndefined = { [K in keyof Person]: NonNullable<Person[K]> };

다양한 컬렉션을 표현하는 타입 생성하기

코드
interface Collection<T> {
  [key: string]: T;
}

type ReadonlyCollection<T> = Readonly<Collection<T>>;
type OptionalCollection<T> = Partial<Collection<T>>;
type RequiredCollection<T> = Required<Collection<T>>;
type ReadonlyOptionalCollection<T> = Readonly<OptionalCollection<T>>;
type ReadonlyRequiredCollection<T> = Readonly<RequiredCollection<T>>;

위 코드에서 Collection<T> 인터페이스는 key 속성이 문자열이고, 값은 T 타입인 객체를 나타낸다.

매핑 타입을 사용하여 Collection<T>에서 파생된 다른 타입들을 만들어낸다.

  • ReadonlyCollection<T>: 모든 속성이 읽기 전용인 컬렉션
  • OptionalCollection<T>: 모든 속성이 선택적인 컬렉션
  • RequiredCollection<T>: 모든 속성이 필수인 컬렉션
  • ReadonlyOptionalCollection<T>: 모든 속성이 읽기 전용이고 선택적인 컬렉션
  • ReadonlyRequiredCollection<T>: 모든 속성이 읽기 전용이고 필수인 컬렉션

매핑 타입을 사용하면 이처럼 쉽게 타입을 변환하고 확장할 수 있다. 또한, 타입스크립트에서 기본적으로 제공되는 매핑 타입 이외에도 사용자가 직접 매핑 타입을 정의할 수 있다. 이를 통해 필요에 따라 더욱 편리하고 유연한 타입을 만들어낼 수 있다.

반응형