스파르타에서 준 타입스크립트 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의 모든 키가 포함되어 있지 않으므로 옵셔널 프로퍼티 문법인 ?를 붙여준다.