Typescript

enum은 자바스크립트에서도 사용할 수 있다

비숑주인 2025. 4. 2. 19:07

TypeScript에는 흔히 쓰는 string, number, boolean 같은 기본 타입 외에도 조금 특별한 타입이 존재한다. 그 중 하나가 바로 enum(열거형)이다.

 

enum이란?

enum은 열거형이라고 불리며, 관련 있는 여러 개의 상수 값을 하나의 그룹으로 묶기 위한 타입이다. 예를 들어, 난이도 단계를 표현하고 싶을 때 아래와 같이 선언할 수 있다

enum Level {
  NOVICE,
  INTERMEDIATE,
  ADVANCED,
  MASTER,
}

 

이 코드에서 Level은 열거형 이름이고, NOVICE부터 MASTER까지는 멤버(member) 라고 한다. 기본적으로 가장 첫 번째 멤버는 0부터 시작하여 순차적으로 증가하는 숫자가 자동 할당된다.

 

자바스크립트로 변환되는 방식

TypeScript의 enum은 자바스크립트로 컴파일될 때 제거되지 않고 아래와 같은 형태의 객체로 남는다:

var Level;
(function (Level) {
  Level[Level["NOVICE"] = 0] = "NOVICE";
  Level[Level["INTERMEDIATE"] = 1] = "INTERMEDIATE";
  Level[Level["ADVANCED"] = 2] = "ADVANCED";
  Level[Level["MASTER"] = 3] = "MASTER";
})(Level || (Level = {}));

 

이 코드는 다음과 같은 객체 구조를 생성한다:

 

var Level = {
  0: 'NOVICE',
  1: 'INTERMEDIATE',
  2: 'ADVANCED',
  3: 'MASTER',
  NOVICE: 0,
  INTERMEDIATE: 1,
  ADVANCED: 2,
  MASTER: 3,
};

 

즉, Level.NOVICE는 0, Level[0]은 'NOVICE'로, 양방향 매핑이 가능하다.

 

값 지정 및 자동 증가 규칙

enum 멤버는 특정 값으로 명시적으로 지정할 수 있다

enum Level {
  NOVICE = 3,
  INTERMEDIATE, // 4
  ADVANCED = 7,
  MASTER,       // 8
}

 

숫자를 지정하지 않으면 이전 멤버의 값에 1을 더한 값이 자동으로 할당된다.

 

문자열 멤버

문자열도 할당할 수 있다. 하지만 하나라도 문자열을 사용하면 모든 멤버에 초기값을 명시적으로 지정해야 한다 

enum Level {
  NOVICE = "BEGINNER",
  INTERMEDIATE = "MID",
  ADVANCED = "EXPERT",
  MASTER = "LEGEND",
}
enum Level {
  NOVICE,
  INTERMEDIATE = "MID",
  ADVANCED = "EXPERT",
  MASTER, // ❌ 초기화 누락으로 컴파일 에러 발생
}

 

enum의 값 활용

enum은 값으로도 활용할 수 있으며, 양방향 매핑을 통해 이름을 추출할 수 있다 

enum Level {
  NOVICE,
  INTERMEDIATE,
  ADVANCED,
  MASTER,
}

const a = Level.NOVICE; // 0
const b = Level[Level.NOVICE]; // "NOVICE"

 

타입으로서의 enum

enum은 타입으로도 사용할 수 있다. 예를 들어 다음과 같은 함수에서 유용하게 쓰인다 

function whatsYourLevel(level: Level) {
  console.log(Level[level]);
}

const myLevel = Level.ADVANCED;
whatsYourLevel(myLevel); // ADVANCED

 

이처럼 enum을 타입으로 사용하면 Level.NOVICE | Level.INTERMEDIATE | ... 와 유사한 유니언 타입 역할을 한다.

 

숫자 enum vs 문자열 enum

enum Role {
  USER,
  GUEST,
  ADMIN,
}

enum Role2 {
  USER = "USER",
  GUEST = "GUEST",
  ADMIN = "ADMIN",
}

 

숫자 enum의 경우 다음처럼 동작한다

function changeUserRole(role: Role) {}

changeUserRole(2); // 가능 (Role.ADMIN)
changeUserRole(4); // ❌ 컴파일 에러 (TypeScript 5.0부터 도입된 stricter check)

 

문자열 enum은 문자열 리터럴 이외의 값은 허용되지 않는다 

function changeUserRole2(role: Role2) {}

changeUserRole2(Role2.USER); // 가능
changeUserRole2("USER1");    // ❌ 에러

 

enum을 브랜드 타입으로 사용하기

enum은 브랜드 속성으로도 사용할 수 있다. 다음은 돈의 종류를 구분하는 예시이다 

enum Money {
  WON,
  DOLLAR,
}

interface Won {
  type: Money.WON;
}

interface Dollar {
  type: Money.DOLLAR;
}

function moneyOrDollar(param: Won | Dollar) {
  if (param.type === Money.WON) {
    // Won 타입
  } else {
    // Dollar 타입
  }
}

 

다만 enum 간의 값이 겹칠 수 있다는 점에 주의해야 한다 

enum Money { WON }         // WON = 0
enum Water { LITER }       // LITER = 0

interface M { type: Money.WON }
interface N { type: Water.LITER }

function moneyOrLiter(param: M | N) {
  if (param.type === Money.WON) {
    // 항상 여기에 들어옴
  } else {
    // 이 블록은 실행되지 않음
  }
}

 

Money.WON과 Water.LITER는 모두 0이기 때문에 런타임에서는 구분이 되지 않는다. 같은 enum 내에서만 비교해야 안전하다.

const enum: 최적화된 enum

TypeScript에서는 const enum을 사용해 enum 객체 자체가 생성되지 않도록 할 수 있다

 

const enum Currency {
  WON,
  DOLLAR,
}

const won = Currency.WON; // 0

 

이 경우 컴파일된 자바스크립트는 다음과 같이 치환된다 

var won = 0;

 

즉, 실제 Currency 객체는 존재하지 않기 때문에 다음은 사용할 수 없다

Currency[Currency.WON]; // ❌ 에러 발생

 


항목 설명
기본 enum 숫자 자동 할당 (0부터 시작), 양방향 매핑 가능
문자열 enum 수동 할당 필요, 단방향 매핑
타입으로 사용 enum을 타입으로 지정 가능 (멤버 유니언 역할)
브랜드 타입 활용 멤버 값으로 인터페이스 구분 가능
const enum 성능 최적화를 위한 방식, 객체 생성 없음
주의점 서로 다른 enum의 값은 런타임에서 구분되지 않을 수 있음

TypeScript의 enum은 자바스크립트 코드로도 남기 때문에 런타임에서도 사용할 수 있으며, 다양한 용도로 활용 가능하다. 하지만 내부 동작 방식과 enum 간 비교 시의 주의사항 등을 잘 이해하고 사용하는 것이 중요하다.