type CountryCode = 'AR' | 'CN' | 'JP' | 'KR' | 'GU' | 'GT' | 'GN' | 'US'
const countryCode: CountryCode = 'AR'
국가 코드가 들어가는 변수에 대한 타입을 지정해줄 때, 위처럼 union type으로 CountryCode를 만들고 이를 변수에서 사용할 수 있다. 그러나 구분하기 쉽지 않기에, value설명으로 key값을 활용하는 방법을 소개한다.
enum타입은 열거형이라고도 부르는데, 특정 값들의 집합(숫자형 vs 문자열형)을 의미한다.
enum ProgrammingLanguage {
Typescript, // 0
Javascript, // 1
Java, // 2
Python, // 3
Kotlin, // 4
Rust, // 5
Go, // 6
}
// 각 멤버에게 접근하는 방식은 자바스크립트에서 객체의 속성에 접근하는 방식과 동일하다
ProgrammingLanguage.Typescript; // 0
ProgrammingLanguage.Rust; // 5
ProgrammingLanguage["Go"]; // 6
// 또한 역방향으로도 접근이 가능하다
ProgrammingLanguage[2]; // “Java”
타입스크립트의 enum은, 각 멤버의 값을 스스로 추론한다. 기본적인 방식은 0부터 1씩 늘려가며 값을 할당하는 것이다.
enum ProgrammingLanguage {
Typescript = "Typescript",
Javascript = "Javascript",
Java = 300,
Python = 400,
Kotlin, // 401
Rust, // 402
Go, // 403
}
또한 각 멤버에 명시적으로 값을 할당할 수 있고, 일부 멤버에 직접 할당하지 않아도 이전 멤버를 기준으로 1씩 늘려가며 자동으로 할당한다. (당연히 문자열 enum은 자동증가 기능이 없다.)
주로 문자열 상수를 생성하는 데 사용된다. 응집력있는 집합 구조체를 만들 수 있으며, 사용자의 입장에서도 간편하게 활용할 수 있다.
또한 열거형은 그 자체로 변수 타입으로 지정할 수 있다. 이때 열거형을 타입으로 가지는 변수는, 해당 열거형이 가지는 모든 멤버를 값으로 받을 수 있다.
enum ItemStatusType {
DELIVERY_HOLD = "DELIVERY_HOLD", // 배송 보류
DELIVERY_READY = "DELIVERY_READY", // 배송 준비 중
DELIVERING = "DELIVERING", // 배송 중
DELIVERED = "DELIVERED", // 배송 완료
}
const checkItemAvailable = (itemStatus: ItemStatusType) => {
switch (itemStatus) {
case ItemStatusType.DELIVERY_HOLD:
case ItemStatusType.DELIVERY_READY:
case ItemStatusType.DELIVERING:
return false;
case ItemStatusType.DELIVERED:
default:
return true;
}
};
checkItemAvailable(ItemStatusType.DELIVERY_HOLD);
checkItemAvailable("DELIVERED"); // Error
// enum ProgrammingLanguage {
// Typescript, // 0
// Javascript, // 1
// Java, // 2
// Python, // 3
// Kotlin, // 4
// }
// ProgrammingLanguage.Rust; // 3
enum ProgrammingLanguage {
Typescript, // 0
Javascript, // 1
Temp, // 2
Java, // 3
Python, // 4
Kotlin, // 5
}
ProgrammingLanguage.Python; // 4
ProgrammingLanguage.Python = 3
→ ProgrammingLanguage.Rust = 4
가 되어버린다. 코드리뷰에서도 무심코 건너가버릴 수 있는 문제 중 하나이다.enum ProgrammingLanguage {
Typescript, // 0
Javascript, // 1
Temp, // 2
Java, // 3
Python, // 4
Kotlin, // 5
}
console.log(ProgrammingLanguage[10000]); // undefined
enum ProgrammingLanguage {
Typescript, // 0
Javascript, // 1
Temp, // 2
Java, // 3
Python, // 4
Kotlin, // 5
}
console.log(Object.keys(ProgrammingLanguage));
// [
// '0', '1',
// '2', '3',
// '4', '5',
// 'Typescript', 'Javascript',
// 'Temp', 'Java',
// 'Python', 'Kotlin'
// ]
Object.values
키워드를 사용해도 동일하다.const enum ProgrammingLanguage {
// ...
}
console.log(Object.keys(ProgrammingLanguage)); // Error
console.log(ProgrammingLanguage[0]); // Error
const enum을 활용해 열거형을 선언해버리면, 리버스 매핑을 막아버릴 수 있다. 자바스크립트에서의 객체에 접근하는 것과 유사하게 동작한다.
이처럼 사용하는데에 주의가 필요하다. 따라서 typescript에선 enum을 사용하면 안된다는 말이 나오고 있으며, 우아한 형제들은 어떻게 받아들이는지 알아보자.
배달이팀 : 딱히 제한은 없는데 enum을 선호하는 편이에요. IDE에서 지원을 다 해주긴 하는데 유니온 타입은 내가 어떤 타입을 가졌는지 전부 기억해야하고, 변경이 필요하면 사용되는 곳을 모두 찾아서 바꿔야할 때가 있어요. 특히 string 타입의 유니온 타입은 리팩터링하기에 번거로운점이 많은 것 같아요. 유니온 타입은 타입이니까 순회가 안 되지만, enum은 값이기 때문에 이터러블하죠.
즉, enum은 값이기 때문에 검증이 가능합니다. 하지만 enum은 정의부를 바꾸면 알아서 사용하는 쪽에서도 변경이 되니까 편한 것 같아요. 그래서 넓은 범위에서 확장해서 써야한다면 enum을 사용하고 있습니다. 또한 코드 가독성이 유니온 타입에 비해서 더 좋은 점도 있는 것 같아요. 우리 팀은 DX(개발경험)적인 측면에서 enum을 더 선호한다고 할 수 있겠네요.
물론, enum은 트리쉐이킹이 안되기때문에 번들 사이즈에 영향을 줄 수 있지만 const enum을 사용하면 해결할 수 있어요. 사실 enum을 쓴다고 해서 전체 파일의 번들 사이즈가 서비스에 영향을 미칠정도는 아니라 크게 고민하진 않아요.
냥이팀 : enum은 잘 사용하지 않았아요. 타입스크립트에서 타입을 선언하는 용도로 enum이 있어야하는지 잘 모르겠어요. enum이 들어갈 수 있는 값을 타입으로 강제해놓고 객체로 만들어야 맞지 않나 하는 생각을 많이 했어요.
enum은 타입을 위한 문법이라기보다 개발을 위한 문법 같아요. enum의 기능이 타입스크립트 컴파일러에 의해 동작하는 것이 이상하게 느껴집니다. 예를 들어 enum의 리버스 매핑 기능은 컴파일러에서 처리되면 안되는 동작이라고 생각해요. 그래서 사용하지 않는 편이에요.
타입스크립트에서 처음 배울 때 타입스크립트를 자바스크립트에서 실행되는 구문이라고 생각해서 에러를 내는 경우가 많은데 enum도 비슷한 것 같아요.
메이팀 : 우리 팀도 enum은 지양하고 있어요. enum은 사용하기엔 되게 편한데 자바스크립트로 컴파일될 때 IIFE로 바뀌는게 크진 않지만 성능에 영향을 줄 수 있다는 것을 본 것 같아서 그 이후론 습관적으로 안 쓰기 시작했어요.
배달이팀 : 우리 팀은 enumaration 폴더를 따로 만들어서 사용하고 있습니다. 이때 이 폴더에 정의한 enum을 외부에서 전역적으로 참조할 때는 const enum을 사용합니다. const enum은 빌드 과정에서 참조 값만 남기기 때문에 트리쉐이킹이 된다는 장점이 있습니다. 또한 어차피 enum도 상수를 쓰기 위한 것으로 생각하기 때문에 const enum을 사용하는게 적절하다고 판단됩니다. 물론 isolate모드를 활성화하고 const enum을 쓰면 안된다는 의견도 있지만, 현재로서는 더 명확하고 정적(static)인 값을 사용할 수 있다는 장점이 더 큰 것 같아요.
왕팀 : 우리는 const enum을 사용하지 않습니다. const enum은 enum과 다르게 직접적인 값으로 치환되기 때문에 전체 네임스페이스에 접근하지 못하고 순회할 수도 없다는 단점을 가지고 있는 것 같아요.
https://velog.io/@jay/typescript-enum-be-careful
https://techblog.woowahan.com/9804/#toc-1