본문 바로가기

[TypeScript] enum vs const enum

by mugglim 2022. 5. 30.

(+ 07/14 객체로 enum 구현 추가 )

enum

enum은 c++, Java 언어에서 사용되는 열거형 타입이다. JavaScript에는 지원되지 않는 문법이며, TypeScript에서만 사용할 수 있다.

enum은 트리 쉐이킹 되지 않는다.

타입스크립트에서 enum은 컴파일 시점에 즉시 실행 함수(IIFE)로 key-value, value-key 쌍의 속성을 가진 객체를 생성한다. 아쉬운점은 IIFE로 객체를 생성하기 때문에 트리 쉐이킹 되지 않아 번들 파일의 크기를 증가시킬 수 있다.

/* TS */
enum EnumKeyboard {
  "UP",        // 0
  "LEFT",      // 1
  "BOTTOM",    // 2
  "RIGHT",     // 3
}

/* JS */
var EnumKeyboard;
(function (EnumKeyboard) {
    EnumKeyboard[EnumKeyboard["UP"] = 0] = "UP";
    EnumKeyboard[EnumKeyboard["LEFT"] = 1] = "LEFT";
    EnumKeyboard[EnumKeyboard["BOTTOM"] = 2] = "BOTTOM";
    EnumKeyboard[EnumKeyboard["RIGHT"] = 3] = "RIGHT";
})(EnumKeyboard || (EnumKeyboard = {}));

enum은 위험하다.

enum은 선언되지 않는 key값의 접근을 허용한다. (단, 숫자 문자열이 아닌 경우에는 접근을 제한한다.)

enum EnumKeyboard {
  "UP",         // 0
  "LEFT",       // 1
  "BOTTOM",     // 2
  "RIGHT",      // 3
}

console.log(EnumKeyboard[100]);           // no-error
console.log(EnumKeyboard['LeftDown']);  // error

const enum

enum의 문제점은 크게 2가지이다. 즉시 실행 함수로 평가되어 트리 쉐이킹이 되지 않아 빌드 파일의 크기가 커진다. 또한, 선언되지 않는 key값의 접근을 허용해버린다.

이와 달리, const enum은 객체를 생성하지 않아 트리 쉐이킹의 문제점이 없고, 존재하지 않는 키 값의 접근을 제한하여 enum보다 안전하게 코드를 작성할 수 있다. (컴파일 시점에 객체를 생성하지 않는 대신 enum을 사용하는 부분을 값으로 치환환다.)

/* TS */
const enum EnumKeyboard {
  "UP",         // 0
  "LEFT",       // 1
  "BOTTOM",     // 2
  "RIGHT",      // 3
}
console.log(EnumKeyboard[100]);              // error !
console.log(EnumKeyboard['LeftDown']);     // error !

/* JS */
console.log(0 /* 'UP' */);                 // enum 객체가 아닌 상수로 치환된다.

const enum의 문제점

하지만 const enum이 완벽한 것은 아니다.

  1. babel이 트랜스파일링 못해, babel-plugin-const-enum 플러그인을 설치해야 한다.
  2. 값을 객체로 생성하는게 아니라, 임의로 변경시 에러를 추적하기 어렵다. (이를 방지하기 위해, preserveConstEnums flag를 true로 변경하면 enum 처럼 객체를 생성한다.)
  3. 문자열 값을 유니코드로 생성하여, 빌드 파일의 크기가 커진다.
/* TS */
const enum EnumKeyboard {
  "GREETING" = "안녕하세요. 반가워요!!"
}
console.log(EnumKeyboard['GREETING']);

/* JS */
console.log("\uC548\uB155\uD558\uC138\uC694. \uBC18\uAC00\uC6CC\uC694!!" /* 'GREETING' */);

객체를 사용하자.

자바스크립트의 객체를 사용하면 트리 쉐이킹 할 수 있다. enum은 value값이 상수이다. 그래서 객체와 as const 키워드를 활용하여 enum을 흉내낼 수 있다. 참고로 as const 키워드를 사용하면 리터럴 타입으로 추론된다. 예를 들어, 객체에 as const를 사용하면 각 속성에 대해 readonly를 부여하여 속성을 삽입 및 수정이 불가하다. 또한, 각 속성의 타입을 리터럴 타입으로 추론한다. 간단히 예시를 확인해보자.

// without as const
const sonny = { name : "sonny"  };
type T = typeof sonny;   // { name: string; }

// with as const
const sonny = { name : "sonny"  } as const;
type T = typeof sonny; // { readonly name: "sonny"; }

이제 객체를 이용해 EnumKeyboard을 enum 키워드를 사용하지 않고 enum을 구현해보자. 참고로 EnumKeyboard은 타입이 아닌 객체이기 때문에 값으로 평가된다. 값을 타입으로 변환하기 위해서는 typeof 연산자를 사용해야 한다.

/* TS */

const EnumKeyboard = {
  "UP" : "UP",     
  "LEFT" : "LEFT",
  "BOTTM" : "BOTTOM",
  "RIGHT" : "RIGHT"
} as const

type Keyboard = typeof EnumKeyboard;
// {   
//     readonly UP: "UP";
//     readonly LEFT: "LEFT";
//     readonly BOTTM: "BOTTOM";
//     readonly RIGHT: "RIGHT";
// }

type KeyboardKeys = keyof typeof EnumKeyboard
// "UP" | "LEFT" | "RIGHT" | "BOTTM"


/* JS */
const EnumKeyboard = {
    "UP": "UP",
    "LEFT": "LEFT",
    "BOTTM": "BOTTOM",
    "RIGHT": "RIGHT"
};

Ref.

댓글