반응형
매핑된 타입
TypeScript는 더 안전한 nextDay 타입을 선언할 수 있는 더 강력한 두 번째 방법도 제공합니다.
바로 매핑된 타입(mapped type)입니다.
매핑된 타입을 이용해 nextDay가 DayOfTheWeek를 키로, Day를 값으로 갖는 객체라고 선언해 보겠습니다.
type DayOfTheWeek = 'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri'
type Day = DayOfTheWeek | 'Sat' | 'Sun'
let nextDay: {[K in DayOfTheWeek]} = {
}
다음과 같은 유용한 에러 메시지를 바로 얻을 수 있습니다.
'{}' 형식에 '{ Mon: any; Tue: any; Wed: any; Thu: any; Fri: any; }' 형식의 Mon, Tue, Wed, Thu, Fri 속성이 없습니다.ts(2739)
매핑된 타입은 TypeScript만의 고유한 언어 기능입니다.
리터럴 타입처럼 매핑된 타입도 JavaScript에 정적 타입을 덧씌우는 도전을 가능케 하는 유틸리티 기능입니다.
살펴본 것처럼 매핑된 타입에는 고유 문법이 있습니다.
인덱스 시그니처와 마찬가지로 한 객체당 최대 한 개의 매핑된 타입을 가질 수 있습니다.
type FirstMappedType = {
[Key in UnionType]: ValueType
}
이름에서 알 수 있듯이 매핑된 타입은 객체의 키와 값 타입을 매핑하는 수단을 제공합니다.
실제로 TypeScript는 내장 Record 타입을 구현하는 데 매핑된 타입을 이용합니다.
type Record<K extends keyof any, T> = {
[P in K]: T
}
매핑된 타입은 Record보다 강력합니다.
객체의 키와 값에 타입을 제공할 뿐 아니라, 키인 타입과 조합하면 키 이름별로 매핑할 수 있는 값 타입을 제한할 수 있기 때문입니다.
매핑된 타입을 어떻게 이용할 수 있는지 간단한 예를 살펴보겠습니다.
type Account = {
id: number
isEmployee: boolean
notes: string[]
}
// 모든 필드를 선택형으로 만듦
type OptionalAccount = {
[K in keyof Account]?: Account[K] // ①
}
// 모든 필드를 nullable로 만듦
type NullableAccount = {
[K in keyof Account]: Account[K] | null // ②
}
// 모든 필드를 읽기 전용으로 만듦
type ReadonlyAccount = {
readonly [K in keyof Account]: Account[K] // ③
}
// 모든 필드를 다시 쓸 수 있도록 만듦(Account와 같음)
type Account2 = {
-readonly [K in keyof ReadonlyAccount]: Account[K] // ④
}
// 모든 필드를 다시 필수형으로 만듦(Account와 연결)
type Account3 = {
[K in keyof OptionalAccount]-?: Account[K] // ⑤
}
- Account의 각 필드를 선택형으로 매핑하면서 새로운 객체 타입 Optional Account를 만들었습니다.
- Account의 각 필드에 null을 할당할 수 있도록 매핑하면서 새로운 객체 타입 NullableAccount를 만들었습니다.
- Account의 각 필드를 읽기 전용으로 매핑하면서 새로운 객체 타입 Readonly Account를 만들었습니다.
- 필드를 선택형(?)이나 readonly로 표시할 수 있음은 물론, 표시를 제거할 수도 있습니다. 매핑된 타입에서만 사용할 수 있는 특별 연산자인 마이너스(-) 연산자를 적용해 readonly 한정자를 제거해 결과적으로 기존 Account 타입과 똑같은 새 객체 타입 Account2를 만들었습니다.
- OptionalAccount에서 마이너스(-) 연산자로 선택형(?) 연산자를 제거하고 원래 Account 타입과 같은 Account3라는 새 객체 타입을 만들었습니다.
마이너스(-)에 대응하는 플러스(+) 타입 연산자도 있습니다.
매핑된 타입에서 readonly는 +readonly를 의미하며 ?는 +?를 의미하므로 사실상 +연산자를 직접 사용하는 상황은 없습니다.
내장 매핑된 타입
매핑된 타입은 매우 유용하여 이 중 많은 것을 TypeScript가 내장 타입으로 제공합니다.
- Record<Keys, Values>
- Keys 타입의 키와 Values 타입의 값을 갖는 객체
- Partial<Object>
- Object의 모든 필드를 선택형으로 표시
- Required<Object>
- Object의 모든 필드를 필수형으로 표시
- Readonly<Object>
- Object의 모든 필드를 읽기 전용으로 표시
- Pick<Object, Keys>
- 주어진 Keys에 대응하는 Object의 서브 타입을 반환
반응형
'👶 TypeScript' 카테고리의 다른 글
고급 함수 타입들 - 튜플의 타입 추론 개선 (0) | 2023.01.20 |
---|---|
컴패니언 객체 패턴(companion object pattern) (0) | 2023.01.20 |
Record 타입 (0) | 2023.01.20 |
객체 타입의 타입 연산자 - keyof 연산자 (0) | 2023.01.19 |
객체 타입의 타입 연산자 - 키인 연산자 (0) | 2023.01.19 |