Languages/TypeScript

TypeScript Enums vs as const

iam102 2024. 4. 21. 14:40

TypeScript를 사용하면서 상수를 지정할 때 enum과 as const의 방식이 있습니다. 팀 단위로 개발을 진행하면서 상수 지정에 대한 컨벤션은 따로 없었고 팀원들의 스타일에 따라 각각 사용 중이었습니다. 상수 지정 방식을 통일하고 해당 내용을 정리할 겸 enum과 as const의 차이를 알아보겠습니다.

 

Enums

enum

예시로 enum을 사용하여 상수를 지정합니다.

// 숫자 열거형
enum Direction {
  // 따로 할당된 값이 없을 경우 0부터 차례로 할당 됨.
  Up,
  Down,
  Left,
  Right,
}

// 문자열 열거형
enum DirectionString {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}

 

숫자 열거형 enum을 사용 시에 가독성은 좋아 보이지만 해당 코드를 transpile 할 경우 아래와 같이 나오게 됩니다.

enum Direction {
  Up,
  Down,
  Left,
  Right,
}
let up = Enum.Up;
let nameOfUp = Enum[up]; // "Up"

// transpile

var Direction;
(function (DIRECTION) {
    DIRECTION[DIRECTION["Up"] = 0] = "UP";
    DIRECTION[DIRECTION["Down"] = 1] = "DOWN";
    DIRECTION[DIRECTION["Left"] = 2] = "LEFT";
    DIRECTION[DIRECTION["Right"] = 3] = "RIGHT";
})(DIRECTION || (DIRECTION = {}));
let up = Enum.Up;
let nameOfUp = Enum[up]; // "Up"

 

위의 코드에서 숫자 열거형 enum은 값에서 필드로 맵핑할 수 있는데 이를 Reverse mappings라고 부릅니다. 아래와 같은 형태로 transpile이 되는 것입니다.

enum Direction {
  Up,
  Down,
  Left,
  Right,
}

// transpile

var Direction = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
  '0': 'Up',
  '1': 'Down',
  '2': 'Left',
  '3': 'Right',
}

 

enum을 transpile 시 필드에 값을 할당하는 함수가 IIFE 형태로 선언되어 있습니다. Tree Shaking에 최적화된 Rollup의 경우 enum을 사용하지 않더라도 transpile 시 IIFE 형태로 선언되어 있어 Tree Shaking 되지 않는 이슈가 있습니다.

 

참고로 문자열 열거형에서는 Reverse mappings가 발생하지 않습니다.

 

const enum

Reverse mappings을 막고 좀 더 엄격하게 관리를 위해 const enum을 사용합니다. 예시로 확인해 보겠습니다.

const enum Direction {
  Up,
  Down,
  Left,
  Right,
}
 
let directions = [
  Direction.Up,
  Direction.Down,
  Direction.Left,
  Direction.Right,
];

// transpile

let directions = [
  0 /* Direction.Up */,
  1 /* Direction.Down */,
  2 /* Direction.Left */,
  3 /* Direction.Right */,
];

 

transpile 시 단순히 enum을 사용하는 것과 달리 불필요한 부분이 없어졌고 이를 통해 Reverse mappings이 일어나지 않고 IIFE가 없어 Tree Shaking에도 이슈가 없습니다. 하지만 const enum은 babel로 transpile 할 수 없고 TypeScript의 설정에 따라 const enum이 제대로 동작을 안 할 수 있습니다.

 

as const

type assertion을 사용하여 as const를 통해 상수를 지정합니다.

const Direction = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
} as const;

type Direction = typeof Direction[keyof typeof Direction];

// transpile

const Direction = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
};

 

as const를 사용하면 앞서 확인했던 TypeScript Enums의 문제점인 Reverse mappings, Tree Shaking 이슈, TypeScript 설정에 따른 이슈 없이 사용할 수 있습니다.

 

마무리

여러 레퍼런스를 참고하거나 TypeScript Enums에서 enum과 const enum 그리고 as const를 직접 확인했을 때 아래와 같은 순서로 상수 지정 방식을 선택할 수 있습니다.

as const > const enum > enum

 

TypeScript Handbook에서도 해당 내용을 볼 수 있습니다.

In modern TypeScript, you may not need an enum when an object with as const could suffice

 

TypeScript를 사용하며 단순히 상수를 지정하는 방식에서도 많은 효율을 올릴 수 있음을 알 수 있습니다. 사소한 부분도 신경을 쓰며 개발해야겠습니다.


참고 자료

https://www.typescriptlang.org/ko/docs/handbook/enums.html

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions

https://velog.io/@logqwerty/Enum-vs-as-const

https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking