자바스크립트에서는 원래 열거형(Enumerated Type, 줄여서 Enum)이 없었는데, 타입스크립트에서 Enum을 제공하면서 사용 가능하게 되었습니다. 위키피디아에서는 enum
을 아래와 같이 설명합니다.
멤버라 불리는 명명된 값의 집합을 이루는 자료형이다. 열거자 이름들은 일반적으로 해당 언어의 상수 역할을 하는 식별자이다.
대표적인 열거형의 예시로 boolean
타입을 들 수 있는데, boolean
타입은 true
와 false
로 이루어진 자료형이에요. 이처럼 실제 코딩을 하면서 제한적 이면서 참 또는 거짓이 아닌 보다 더 다양한 상태를 정의하고 싶다면 enum
을 사용하여 정의할 수 있습니다.
타입스크립트에서 enum
을 선언하려면, enum
이라는 키워드를 통해 선언할 수 있습니다.
enum Direction {
EAST,
WEST,
SOUTH,
NORTH
}
function setDirection(direction: Direction) { // 선언한 enum은 타입으로 사용이 가능하다.
// ...
}
Direction
이라는 enum
을 생성하고, 아래의 setDirection
이라는 함수의 인자로 Direction
이라는 타입을 설정했어요. 위의 코드처럼, enum
은 타입으로써도 사용할 수 있습니다. VSCode에서 함수의 파라미터인 direction
으로 자동완성부분을 보면,
number
타입의 method
들이 자동완성 목록으로 제공되는걸 볼 수 있어요. 이를 통해 알 수 있는 사실은, enum의 각각 속성의 값들은 숫자를 값으로 가지는 것을 알 수 있습니다.
enum Direction { // #1
EAST,
WEST,
SOUTH,
NORTH
}
// 실제로 값을 입력하지 않았을 뿐, 타입스크립트는 값을 아래와 같이 자동으로 입력해준다.
enum Direction { // #2
EAST = 0,
WEST = 1,
SOUTH = 2,
NORTH = 3,
}
enum
은 각각 속성들의 값을 지정하지 않으면, 위에서 아래로 0부터 숫자 1씩 늘어나도록 자동으로 설정이 됩니다. 만약 직접 값을 설정하고 싶다면, 위의 코드 예시 중 2번처럼 각각 속성에 값을 입력하면, 값을 설정할 수 있습니다.
enum Direction {
EAST = 3,
WEST, // 4
SOUTH = EAST + WEST, // 7
NORTH = SOUTH + 5, // 12
}
처음에 enum
을 선언할 때 초기 값을 직접 설정할 수 있어요. 값을 설정하지 않으면, 이전 속성에서 1을 더한 값이 되고, 표현식으로도 설정할 수 있습니다.
enum Direction {
EAST = 'East',
WEST = 'West',
SOUTH = 'South',
NORTH = 'North',
}
또한 속성의 값으로 문자열을 설정할 수 있습니다.
위의 예시 코드들을 통해 알 수 있는 사실은, enum
을 통해 생성한 속성 들의 값으로 숫자 또는 문자열을 설정 할 수 있습니다. 정리하자면, enum
으로 생성한 속성들은 문자열 또는 숫자로만 설정이 가능합니다. 물론 문자열과 숫자를 섞어서 사용할 수도 있습니다.
선언한 enum
의 각각 속성의 값이 숫자인 경우, 역 매핑을 지원합니다. 예제 코드를 먼저 보겠습니다.
enum Direction {
EAST,
WEST,
SOUTH,
NORTH,
}
const East = Direction.EAST;
const valueOfEast = Direction[East]; // EAST
가장 마지막 줄을 보면, valueOfEast
의 값은 ‘EAST’
입니다. 왜 이런 결과가 발생했는지를 알기 위해선, 타입스크립트가 어떻게 컴파일 하는지(트랜스 파일링)를 확인해봐야 합니다.
var Direction;
(function (Direction) {
Direction[Direction["EAST"] = 0] = "EAST";
Direction[Direction["WEST"] = 1] = "WEST";
Direction[Direction["SOUTH"] = 2] = "SOUTH";
Direction[Direction["NORTH"] = 3] = "NORTH";
})(Direction || (Direction = {}));
const East = Direction.EAST;
const valueOfEast = Direction[East];
컴파일된 코드를 보면, 정방향과 역방향 모두 저장되어있는 것을 볼 수 있습니다. 조금 더 정리해서 코드를 나열해보면,
var Direction = {
EAST: 1,
WEST: 2,
SOUTH: 3,
NORTH: 4,
'1': 'EAST',
'2': 'WEST',
'3': 'SOUTH',
'4': 'NORTH',
}
위와 같이 접근이 가능하도록 타입스크립트에서 컴파일 합니다. 그러므로 역 매핑의 첫 번째 코드 예시와 같이 값에 접근할 수 있게 된 이유에요.
const enum
은 기존의 enum
보다 더 가성비있고 엄격한 키워드로, 선언 방법과 컴파일 시에 어떤 결과를 내는지 바로 코드 예제를 통해 알아보겠습니다.
// #1 코드 작성 시점
const enum Direction {
EAST,
WEST,
SOUTH,
NORTH,
}
const East = Direction.EAST;
const West = Direction.WEST
// #2 컴파일 시점
const East = 0 /* Direction.EAST */;
const West = 1 /* Direction.WEST */;
const enum
은 enum
과 다르게, 선언한 enum
이 컴파일된 후에는 사라진 것을 알 수 있습니다. 더 엄격한 이유는 역매핑 또한 되지 않기 때문입니다. 컴파일 하는 순간 선언한 부분에만 인라인 되고, enum
을 선언한 부분은 컴파일 후 삭제가 됩니다.
const assertion(상수 단언)은 타입의 범위를 좁혀줍니다. 지금까지 사용했던 Direction
예제를 통해 상수 단언 이전에 비교를 먼저 해보면,
// #1 선언부
const Direction = {
EAST: 0,
WEST: 1,
SOUTH: 2,
NORTH: 3,
};
// #2 타입스크립트의 타입 추론
const Direction: {
EAST: number;
WEST: number;
SOUTH: number;
NORTH: number;
}
Direction
속성의 값들을 숫자로 입력 했을 때, 타입스크립트는 각각의 값들의 타입을 number
로 추론합니다. 만약 해당 변수 Direction
에 상수 단언을 하면,
// #1 선언부
const Direction = {
EAST: 0,
WEST: 1,
SOUTH: 2,
NORTH: 3,
} as const;
// #2 타입스크립트의 타입 추론
type const = {
readonly EAST: 0;
readonly WEST: 1;
readonly SOUTH: 2;
readonly NORTH: 3;
}
타입스크립트가 타입 추론을 한 부분을 보면 확연한 차이를 볼 수 있습니다. 몇 가지 차이가 있지만, 대표적으로 각 속성값의 타입이 number
가 아닌, 특정 값을 타입으로 추론했습니다. 그리고, readonly
키워드를 보면 알 수 있듯, 각각의 속성을 변경할 수 없도록 추론 합니다.
상황에 따라 다르지만, 각각의 특징을 통해 사용을 고려보는 것이 좋다고 생각해요.
enum
을 컴파일 하면 즉시 실행 함수(IIFE)가 되는데, Rollup
과 같은 번들러는 즉시 실행 함수를 ‘사용하지 않는 코드'라고 판단할 수 없기 때문입니다.)object
타입의 코드로 컴파일 된다.readonly
로, 선언한 값을 타입으로 추론한다.타입스크립트 공식 문서에서는, 어떤 것을 쓸지를 고민하는 사람들에게 아래와 같이 설명했습니다.
In modern TypeScript, you may not need an enum when an object with
as const
could suffice
감히 정리해보자면, as const
(const assertion)으로 충분히 사용하고 있다면, enum
은 필요하지 않을 수 있다라고 설명하는 것 같네요.
평소에 코딩할 때 enum
과 record type
을 정해놓은 기준 없이 사용 했었는데, 코드의 일관성을 위해서 어떤 기준을 가지고 사용하는 게 좋을지 고민하다가, 생각보다 다양한 선택지가 있었고, 그에 따른 특징도 있다는 걸 이제야 알게 되었어요.. 위의 자료들을 찾아보면서 반성 하면서, 동시에 많이 배우기도 한 것 같아요.
처음에는 기준을 찾고자 시작했어요. 제가 구글 검색을 잘 못한 탓도 있는지, 대중적으로 널리 사용하는 기준에 대해서는 찾지 못했어요. 조금 허무하지만, 의외의 차이점과 특징을 알게 되어 오히려 더 좋았습니다.
공부 하면서 정리한 자료라 틀린 내용이 있을 수 있어요. 댓글 남겨주시면 감사하겠습니다!
https://www.typescriptlang.org/docs/handbook/enums.html#handbook-content
https://hyunseob.github.io/2017/07/18/typescript-enums/
https://medium.com/@seungha_kim_IT/typescript-3-4-const-assertion-b50a749dd53b
https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking/