스파르타에서 준 타입스크립트 enum 퀴즈를 풀어보며 또 한번 타입스크립트 기초가 부족하다는 걸 깨달았다. 문제를 풀면서 고민하고 배운 점들을 의식의 흐름대로 정리해보고자 한다.
enum Color {
Red,
Blue,
Black,
}
enum Car {
Sedan,
Truck,
Coupe,
}
type Inventory = {}; // 객체 내부에 Car enum 사용해서 지정해야 함
const inventory: Inventory = {
Sedan: "Red",
Truck: "Black",
};
inventory 객체의 key인 Sedan과 Truck을 Car enum에 해당하는 값으로 쓰도록 타입을 지정해야 한다.
처음에는 enum
의 키를 동적으로 가져오기 위해 인덱스 시그니처([key:Car]
)를 사용하려고 했지만 인덱스 시그니처는 string
, number
, symbol
, Template literal
만 가능하다.
두 번째 방법으로 [key in Car]
를 적용해봤지만 에러가 발생한다.
Object literal may only specify known properties, and 'Sedan' does not exist in type 'Inventory'.
결론적으로 Enum 값을 객체의 키로 사용하고 싶으면 keyof typeof
을 사용하면 된다.
keyof
은 객체의 키를 유니언 타입으로 변경해주는 typescript 연산자다.
(✅ js에는 keyof
이 없다!)
enum
에서는 keyof
을 단독으로 사용할 수 없고 typeof
과 함께 써야(=keyof typeof
) 키를 유니언 타입으로 변경해서 객체에 사용할 수 있다.
(참고: 타입스크립트 핸드북)
그러나 여전히 의문이 남아 있었는데... 🤔
자세한 설명을 아래 stackOverflow에서 찾았다!
스택오버플로우의 답변에 의하면 다음과 같다.
(참고: What does "keyof typeof" mean in TypeScript?)
typeof
연산자는 자바스크립트와 타입스크립트에서 다르게 작동한다.
type Language = 'EN' | 'ES';
const userLanguage: Language = 'EN';
const preferences = { language: userLanguage, theme: 'light' };
console.log(typeof preferences); // "object"
type Preferences = typeof preferences;
// type '{language: 'EN''; theme: string; }'
위의 예시를 보면 자바스크립트에서는 typeof
연산자의 결과로 object
가 반환된다.
타입스크립트에서는 preference 객체의 형태 그대로가 반환된다는 것을 알 수 있다.
여기서 enum
의 특성을 알아야 한다❗
enum
은 런타임 상태에서 구체적인 타입이 아닌 object
로 취급된다는 점이다.
따라서 자바스크립트로 런타임되기 전 타입스크립트 상태에서 typeof
연산자를 통해 enum
이 가진 구체적인 객체 타입으로 변환해야 한다. 그리고 나서 타입스크립트의 keyof
연산자를 적용해야 enum
의 key 값들을 리터럴 유니온으로 가져올 수 있게 된다.
이것이 바로 enum
의 키를 불러오기 위해 keyof typeof
연산자를 써야하는 내 나름의 해석이다. (틀린 점이 있다면 댓글로 알려주세요!)
type Inventory = {
[key in keyof typeof Car]?: keyof typeof Color;
};
const inventory: Inventory = {
Sedan: "Red",
Truck: "Black",
};
keyof typeof
연산자를 붙인 후에는 in
연산자를 포함해서 Car 객체의 모든 키를 열거하도록 한다.
inventory의 키에는 Car의 모든 키가 포함되어 있지 않으므로 옵셔널 프로퍼티 문법인 ?
를 붙여준다.