TS 탐구생활 - TS의 enum 타입
- typescript
1. enum 타입 기본
1.1. 기본적인 타입 선언
enum
타입은 ts에는 없지만 ts에서 사용되는 값이다. 몇몇 다른 언어에서의 열거형과 같이 여러 상수를 묶어서 하나의 타입으로 정의할 수 있다. 이렇게 하면 Red는 0, Green은 1, Blue는 2와 같이 자동 매핑되어 사용할 수 있다. 이런 식으로 실제 값이 숫자인 enum을 숫자형 enum이라고 한다.
문자열 enum도 있는데 이는 enum의 각 멤버들을 문자열 리터럴 혹은 다른 문자열 enum의 멤버로 상수 초기화해야 한다. 이렇게 하면 디버깅 시 좀 더 확실하고 의미있는 값을 볼 수 있다는 장점이 있다.
다른 상수를 직접 enum 값으로 매핑할 수도 있다. 만약 숫자를 매핑한 경우 뒤따르는 멤버들은 자동으로 1씩 증가된 값을 매핑받는다. 만약 문자열을 매핑한 경우에는 그 다음 멤버부터는 직접 매핑해야 한다.
하지만 이전에 문자열 매핑을 했더라도 이후에 숫자 매핑을 하게 되면 그 이후 멤버는 다시 문자열을 직접 매핑해 줄 때까지 자동으로 숫자 매핑된다. 이런 식으로 문자열과 숫자를 섞어서 쓰는 것을 이종 enum(heterogeneous enum)이라고 하는데 이는 특별히 그렇게 할 이유가 없는 경우 권장되지 않는다.
1.2. 계산된 값 넣기
이후 다루겠지만 enum은 결국 JS 객체이다. 때문에 상수뿐 아니라 계산된 값을 넣을 수도 있다.
그럼 어떤 경우에 계산된 값으로 취급될까? 상수가 아닐 경우 enum은 계산된 값으로 취급되는데 이 상수란 다음과 같은 것들이다.
- 리터럴(문자, 숫자)
- 다른 상수 enum 멤버의 참조
- 괄호로 묶인 상수 표현식
- 상수 표현식에 단항 연산자
+
,-
,~
가 붙은 경우 - 상수 표현식을 이항 연산자
+
,-
,*
,/
,%
,<<
,>>
,>>>
,&
,|
,^
의 피연산자로 쓴 경우
즉 위와 같은 값들이 아닌 경우 enum의 멤버는 계산된 값으로 취급되고 이후에 볼 const enum에서도 쓸 수 없다.
1.3. 사용
enum 타입은 다음과 같이 값 대신으로 사용할 수 있다.
혹은 함수 인수로 특정 값만 강제하도록 해야 할 때 사용할 수 있다. 이렇게 하면 changeColor
함수 내부에서 color
에는 Color
타입의 값만 들어올 수 있다.
Color
의 key로 접근해서 실제 enum 멤버의 이름을 얻어낼 수도 있다. 이를 역 매핑이라고 한다.
전반적으로 어떤 값의 범주로 제한해야 할 때 사용할 수 있다.
그런데 이런 생각이 들 수 있다. 우리는 이미 이런 기능을 유니언 타입으로 구현할 수 있지 않았나? 다음과 같이 말이다.
그렇다면 enum 타입은 어떤 장점이 있을까? 사실 결론부터 말하면 실용적인 엄청난 장점은 없다. 하지만 일단 enum의 원리부터 알아보고 그쪽으로 넘어가 보자.
2. enum 타입의 동작
일반적으로 타입 선언과 사용들은 모두 JS 코드로 변환되지 않고 사라졌다. 하지만 enum은 다르다. 다음과 같이 enum을 선언하면 JS 코드로 변환되어 남는다.
2.1. enum 타입의 JS 변환
위 타입 선언은 다음과 같이 IIFE로 변환되는 것을 볼 수 있다.
이는 실제로는 다음과 같은 객체를 만들어서 0
과 "Red"
, 1
과 "Green"
, 2
와 "Blue"
를 매핑해 놓은 것과 같다.
JS에서는 enum을 원래 지원하지 않는데 런타임에 사용할 수 있는 enum과 같은 객체를 만들기 위해서 이런 트리키한 방법이 사용되었다고 생각한다.
그럼 이런 객체를 실제로는 만들지 않도록 할 수는 없을까? const enum
을 쓰면 가능하다.
2.2. const enum
const enum
을 쓸 시 JS 코드로 변환되지 않고 그냥 값으로 쓰이게 된다.
숫자 enum의 경우 숫자를 통해서도 해당 enum 멤버를 얻어낼 수 있는 역 매핑이 원래는 가능했다. 하지만 const enum의 경우 이 역 매핑이 불가능하다. 이는 const enum이 컴파일 시점에 사라지기 때문이다.
3. enum 타입의 활용
3.1. 유니언 타입처럼 사용하기
enum은 값으로 사용할 수도 있지만 일반적으로 타입으로 사용된다. 이는 다음과 같이 사용할 수 있다.
3.2. 브랜딩 속성으로 활용
enum은 브랜딩 속성으로 활용할 수 있다. 브랜딩 속성이란 객체의 구분을 위한 속성을 말한다. 이렇게 브랜드 속성으로 enum 멤버를 쓸 수 있다.
주의할 점은 같은 enum 멤버를 사용해야 확실히 구분할 수 있다는 점이다. 다음과 같이 PERSON
과 DOG
가 다른 enum에서 정의되면 둘 다 실제 값은 0
으로 취급될 것이라서 구분할 수 없다.
물론 직접 값을 정의해 준 경우에는 구분될 것이다.
const enum
을 쓸 시 JS 코드로 변환되지 않고 그냥 값으로 쓰이게 된다.
참고
ts handbook - Enums https://www.typescriptlang.org/ko/docs/handbook/enums.html
TypeScript enums vs. types: Enhancing code readability https://blog.logrocket.com/typescript-enums-vs-types/#using-enums-reverse-mapping