enum — 숫자 enum, 문자열 enum, const enum의 차이
enum은 관련된 상수들의 집합 에 이름을 붙이는 TypeScript 고유 기능입니다.
숫자 enum(Numeric Enum)
// 기본값은 0부터 자동 증가
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
console.log(Direction.Up); // 0
console.log(Direction[0]); // 'Up' (역방향 매핑)
// 시작값을 지정하면 그 이후부터 증가
enum StatusCode {
OK = 200,
Created = 201,
BadRequest = 400,
NotFound = 404,
}
역방향 매핑(Reverse Mapping)
숫자 enum은 값에서 이름으로 역방향 조회가 가능합니다.
enum Color {
Red, // 0
Green, // 1
Blue, // 2
}
console.log(Color.Red); // 0
console.log(Color[0]); // 'Red'
console.log(Color[1]); // 'Green'
컴파일된 JavaScript를 보면 양방향 매핑이 어떻게 구현되는지 알 수 있습니다.
// 컴파일 결과
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
문자열 enum(String Enum)
enum EventType {
Click = 'CLICK',
Hover = 'HOVER',
Scroll = 'SCROLL',
}
console.log(EventType.Click); // 'CLICK'
// console.log(EventType['CLICK']); // ❌ 역방향 매핑 없음
문자열 enum은 역방향 매핑이 **없습니다 **. 대신 디버깅할 때 값이 의미를 가지므로 더 읽기 쉽습니다.
숫자 vs 문자열 enum
| 특성 | 숫자 enum | 문자열 enum |
|---|---|---|
| 기본값 | 0부터 자동 증가 | 모든 값 직접 지정 필요 |
| 역방향 매핑 | 가능 | 불가능 |
| 디버깅 | 값이 숫자라 의미 파악 어려움 | 값이 문자열이라 직관적 |
| 번들 크기 | 더 큼 (양방향 매핑 코드) | 상대적으로 작음 |
const enum
const enum은 컴파일 시 ** 완전히 인라인 **됩니다. JavaScript에 enum 객체가 남지 않습니다.
const enum Size {
Small = 'S',
Medium = 'M',
Large = 'L',
}
const shirt = Size.Medium;
// 컴파일 결과 — enum 객체가 없음!
const shirt = 'M'; // 값이 직접 인라인됨
const enum의 제약
const enum Direction {
Up, Down, Left, Right
}
// ❌ 역방향 매핑 불가 (런타임에 객체가 없으므로)
// Direction[0]; // Error
// ❌ 변수로 동적 접근 불가
// const key = 'Up';
// Direction[key]; // Error
면접 포인트:
const enum을 쓰면 번들 크기가 줄어들지만,isolatedModules옵션과 함께 쓸 수 없는 경우가 있습니다. Babel이나 esbuild 같은 트랜스파일러는 파일 단위로 컴파일하므로const enum의 교차 파일 인라이닝이 불가합니다.
enum의 함정
숫자 enum의 타입 안전성 문제
enum Status {
Active = 0,
Inactive = 1,
}
// ⚠️ 아무 숫자나 할당 가능 — 타입 안전하지 않음!
const status: Status = 42; // 에러가 나지 않음!
공부하다 보니 이 부분에서 많이 놀랐습니다. 숫자 enum은 어떤 숫자든 할당할 수 있어서 타입 안전성이 깨질 수 있습니다. 문자열 enum이나 리터럴 유니온을 쓰는 것이 더 안전합니다.
트리쉐이킹 문제
일반 enum은 IIFE(즉시 실행 함수)로 컴파일되기 때문에, 번들러가 사용하지 않는 enum을 제거(트리쉐이킹)하지 못할 수 있습니다.
대안: 리터럴 유니온 + 객체
// 리터럴 유니온 — 가장 가벼운 대안
type Direction = 'up' | 'down' | 'left' | 'right';
// 값이 필요하면 as const 객체
const Direction = {
Up: 'up',
Down: 'down',
Left: 'left',
Right: 'right',
} as const;
type Direction = (typeof Direction)[keyof typeof Direction];
// 'up' | 'down' | 'left' | 'right'
// 사용
function move(dir: Direction) {
console.log(dir);
}
move(Direction.Up); // 'up'
move('down'); // 'down' — 직접 문자열도 가능
이 패턴은 트리쉐이킹이 잘 되고, 숫자 enum의 타입 안전성 문제도 없습니다.
enum을 언제 써야 하나
// ✅ enum이 적합한 경우
// 1. 양방향 매핑이 필요할 때
enum HttpStatus {
OK = 200,
NotFound = 404,
}
console.log(HttpStatus[200]); // 'OK' — 역방향 매핑 활용
// 2. 기존 코드베이스와의 호환
// Angular 등 enum을 널리 사용하는 프레임워크
// ✅ 리터럴 유니온이 적합한 경우
// 1. 단순한 문자열/숫자 상수 집합
type Theme = 'light' | 'dark' | 'system';
// 2. 트리쉐이킹이 중요한 프론트엔드 프로젝트
// 3. 라이브러리 개발 (소비자가 enum에 의존하지 않도록)
정리
- 숫자 enum은 역방향 매핑이 가능하지만 타입 안전성이 약하다
- 문자열 enum은 역방향 매핑이 없지만 디버깅이 쉽다
const enum은 인라인되어 번들 크기를 줄이지만 제약이 있다- 리터럴 유니온 +
as const객체가 현대적인 대안이다 - 면접에서는 enum의 컴파일 결과와 트리쉐이킹 문제를 알면 좋다
댓글 로딩 중...