ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeScript Enums vs as const
    Languages/TypeScript 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

     

Designed by Tistory.