oris9
[Typescript] Enum 타입에 대해 알아보자 (단점, 주의사항, const enum) 본문
짧게 요약 정리를 위쪽에서 하고 자세한 단점에 대한 내용은 아래 추가글로 정리해보려고한다
일단 개념이 필요하신 분들은 위에만 읽고 넘어가셔도 좋을 것 같다
이 단점은 tree-shaking , 즉 번들링과정에서 사용하지 않는 코드를 제거함에 대한 문제를 담고있다
타입스크립트에서의 Enum은,
enum 숫자형이넘 {
숫자형 = 1,
숫자 = 2,
}
enum 문자열이넘 {
문자열 = "foo",
문자 = "foooooot",
}
과 같이 사용할 수 있다.
이넘은 이렇게 어떠한 숫자나 문자, 상수 집합을 의미하는 데이터 타입이고,
여러 개의 상수를 묶어서 관리할때 사용하게된다!
가독성이 좋고 유지관리가 편하지만 유연성은 떨어진다는 특징이 있다. ( -> 한번 선언하고 나면 수정이 어렵다)
숫자형이넘은 모든 값이 명시적으로 초기화 되지 않아도, 자동적으로 값이 할당되는 특징을 가지고 있다.
(기본적으로 증가되는 숫자값을 가지게 된다, 모든 값이 초기화되지 않으면 0, 1, 2, 3 ...
만약 처음 값이 6이라면 6, 7, 8, 9. ...
문자형이넘은 모두 명시적으로 초기화가 필수로 되어야한다!)
또한 숫자형 이넘만 `역매핑`이라는 특별한 기능이 지원되는데, 이 자동 초기화 기능때문에 가능한 것이다.
//역매핑, 리버스매핑
enum Enum {
A;
}
let a = Enum.A; // 0
let keyName = Enum[a]; // A
하지만 enum 방식은 TS에서 JS로 변환되는 트랜스파일링 후, 번들링 과정에서 최적화문제가 발생할 수 있다.
이를 해결하기 위해서 enum을 선언할때 앞에 const를 붙여 해결할 수 있다.
const enum 방식으로 선언해주면,
결과물의 코드양이 줄어들게 된다.
(하지만 const 방식은 속성 값 정의 방식을 사용할 수 없고, 항상 속성에 고정 값만 넣어주어야 한다는 주의점이 있으니 알아두자 ! )
번들러가 tree-shaking을 지원한다 ( 고려해야하는 상황이라면 )
Union type > const enum 또는 string일 경우 const enum, number가 들어갈 경우 union을 사용하거나 해서 조절
( 2020년 Line 블로그에서는 번들성능관점에서 Union Types > const enum > enum 순으로 권장한다 )
** Union Type (합집합, A ∪ B) : type Marvel = "IronMan" | "Hulk";
어떻게 변환되는지 궁금하다면,,,
const enum으로 선언하면 왜 괜찮은지 궁금하다면,,, 왜 const enum시에 속성에 고정 값만 넣어줘야하는 지 궁금하다면,,,
아래까지 읽어주세요
enum은 ts에서 자체적으로 구현했기 때문에 코드를 트랜스파일하면 아래와 같은 코드가 된다.
export enum MOBILE_OS {
IOS,
ANDROID
}
// 문자열을 할당한 경우
export enum MOBILE_OS {
IOS = 'iOS',
ANDROID = 'Android'
}
<<< ts
---------------- 트랜스파일링 -------------------
>>> js
export var MOBILE_OS;
(function (MOBILE_OS) { // !!!!!!!! IIFE(즉시 실행 함수)
MOBILE_OS[MOBILE_OS["IOS"] = 0] = "IOS";
MOBILE_OS[MOBILE_OS["ANDROID"] = 1] = "ANDROID";
})(MOBILE_OS || (MOBILE_OS = {}));
// 문자열을 할당한 경우
export var MOBILE_OS;
(function (MOBILE_OS) {
MOBILE_OS["IOS"] = "iOS";
MOBILE_OS["ANDROID"] = "Android";
})(MOBILE_OS || (MOBILE_OS = {}));
잘 보이라고 주석을 달아놓은 것과 같이..
즉시실행함수를 만들어 enum을 구현하게 된다.
그런데 다양한 번들러들은 (2020년 라인블로그에서는 Rollup과 같은 번들러라고 소개하고 있다! - 번들러에 대해서는 아직 많이 몰라서 다른 블로그 글에 의존해서 적는다) IIFE를 '사용하지 않는 코드'라고 판단할 수 없어서 Tree-shaking ( ** 사용하지 않는 코드를 제거하는 부분, 죽은 잎 떨구기) 이 되지 않는다고 한다.
실제로 저 코드가 사용되지 않는다고 하더라도 최종 번들에 포함되게 되는 것이다.
-- > 최근 글을 더 찾아보니 번들러의 종류나 버전, 아니면 interface안에 enum을 조건으로 넣는다거나 하는 다양한 상황에 따라서 IIFE가 생길 수도 있고 생기지 않을 수도 있는 것 같다. 무조건 생긴다고 생각하면 안될거같고, 최근 번들링도구라고 해서 무조건 안생긴다고 생각해서도 안될듯..
const enum은
const enum MOBILE_OS {
IOS = 'iOS',
ANDROID = 'Android',
}
const ios = MOBILE_OS.IOS
<<< ts
---------------- 트랜스파일링 ----------------
>>> js
const ios = "iOS"
와 같은 형태로 union type과 동일하게 인라인으로 확장되어 트랜스파일된다
Tree-shaking에서도 동일하게 사용하지 않으면 번들에 포함되지 않기 때문에 일반 enum에 비해서 좋다
하지만
const enum을 사용하는 경우 일반 상수로 치환이 되기 때문에 실제 런타임에 실행되는 코드에서 코드 에러를 유발할 수 있고,
이를 방지하기 위하여 tsconfig compilerOptions에 isolatedModules 설정을 true로 설정하는 경우 const enum 또한 enum과 동일하게 즉시실행함수(IIFE)가 생성될 수 있기에 실행될때 100% 권장되지는 않는다고 한다.
또한 const enum은 babel 로 트랜스파일 될 수 없다.
( babel-plugin-const-enum를 사용하여 const enum → enum 또는 const enum → const object로 변경을 진행 시켜서 사용해야한다 )
++++
아니면
이렇게 as const도 가능~!
export const orderStatusKeys = {
주문대기중: 'received',
주문완료: 'accepted',
제작중: 'making',
픽업완료: 'completed',
취소된주문: 'canceled',
} as const;
export type OrderStatusUnion =
typeof orderStatusKeys[keyof typeof orderStatusKeys];
참고
https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking
https://www.kabuku.co.jp/developers/good-bye-typescript-enum