개요

TypeScript에서 enum, const enum, as const는 값 집합을 선언하고 타입으로 활용하기 위한 서로 다른 도구임 각 특성의 차이와 트레이드오프를 이해하면 가독성과 안정성을 챙기면서 번들 크기와 도구 호환성 문제도 피할 수 있음

enum 개념과 동작

  • 열거형 타입을 선언하는 문법
  • 숫자 기반과 문자열 기반 모두 지원
  • 컴파일 결과로 양방향 매핑을 담은 JS 객체 생성
    • 키로 값 조회, 값으로 키 역조회 가능

예시

enum BooleanType {
  False = 0,
  True = 1,
}

컴파일 결과는 즉시실행함수 형태로 양방향 맵 객체 생성됨

var BooleanType = { 0: "False", 1: "True", False: 0, True: 1 };

주의점

  • 멤버 이름에 숫자 이름 사용 불가
    • 예) enum X { 1: ‘A’ } 에러 발생

멤버 종류

  • Constant Member: 고정 상수값 보유
  • Computed Member: 표현식 평가 결과를 값으로 가짐

값 타입별 종류

  • Numeric enum
  • String enum
  • Heterogeneous enum (숫자와 문자열 혼합 사용, 특별한 이유 없으면 지양)

자동 할당

  • 첫 멤버 미초기화 시 0부터 시작
  • 이전 멤버가 숫자 상수면 다음 미초기화 멤버는 이전값 + 1 할당
enum Direction {
  Up, // 0
  Down, // 1
  Left, // 2
  Right, // 3
}

장점

  • 의도 표현력 높음, 양방향 매핑으로 상수 집합을 하나의 식별자로 추상화 가능
  • 정의된 값만 사용하도록 강제 가능, 오입력 방지에 유리

단점

  • 컴파일된 JS 코드가 객체와 초기화 로직을 포함하여 번들 크기 증가
  • IIFE로 생성되는 사이드이펙트 때문에 일반적으로 트리 셰이킹에 취약

const enum

enum의 코드 비용과 간접 참조 비용을 줄이는 목적의 변형 문법 핵심 특징

  • 멤버 접근 지점에 값이 인라인됨
  • 컴파일 시 enum 구현체가 제거됨
  • Computed Member 금지, 상수 표현식만 허용

예시

const enum Direction {
  Up,
  Down,
}
const xs = [Direction.Up, Direction.Down];

컴파일 결과에서 배열 리터럴에 숫자 값이 직접 인라인됨

  • 멤버는 문자열 리터럴 접근으로만 사용 가능하지 않은 방식은 에러 발생

장점

  • 실행 시 오브젝트 생성 비용 제거, 번들 크기 감소 가능

주의 및 함정

  • 빌드 파이프라인에서 트랜스파일러가 const enum 인라인을 보장하지 않으면 깨짐
    • 예) 일부 Babel, isolatedModules 환경, 타입 정보 손실되는 트랜스파일 경로 등
  • 라이브러리 경계 넘어 사용하는 경우 소비자 빌드 설정에 따라 오류 유발 가능 이유로 프로덕션 코드베이스에서 const enum 사용을 제한하거나 금지하는 팀이 많음

as const

TypeScript 3.4의 const assertion 문법 목적

  • 값의 타입 추론 범위를 리터럴 단위로 좁히기 위한 선언적 방법
  • 객체, 배열, 중첩 구조를 포함해 값 전반을 상수로 취급하게 함

핵심 효과

  • 문자열/숫자 값이 리터럴 타입으로 고정됨
  • 객체 수준으로 사용 시 프로퍼티에 readonly 적용됨

간단 예시

const s = "NLP" as const; // 타입이 'NLP'로 고정

const obj = { a: 1, b: "x" } as const;
// obj.a: 1, obj.b: 'x', 모두 readonly

let으로 선언한 값에도 as const를 붙이면 리터럴 타입으로 고정됨

  • 재할당 또는 변경 시 타입 오류 또는 readonly 위반으로 막힘

Discriminated Union과의 결합

조건 분기에서 안전하게 속성을 접근하려면 판별 가능한 유니온이 유용함

  • 공통 판별 키 kind 등으로 각 분기를 좁혀 타입 안전한 접근 보장
  • as const로 리터럴 값을 고정하면 판별 키가 확정되어 오류 제거에 도움

예시

type Shape = { kind: "circle"; radius: number } | { kind: "square"; x: number };

function area(s: Shape) {
  if (s.kind === "circle") return Math.PI * s.radius * s.radius;
  return s.x * s.x;
}

객체 리터럴 작성 시 kind 값을 as const로 고정하면 판별 정확도 향상

const enum 대체 패턴(as const 기반)

const enum 없이도 값 집합을 타입으로 뽑아 쓰는 패턴

const BooleanType = { False: 0, True: 1 } as const;

type BooleanTypeValue = (typeof BooleanType)[keyof typeof BooleanType]; // 0 | 1

특징

  • 런타임 객체는 단방향 매핑만 가짐
  • 타입은 값 집합의 유니온으로 안전하게 반영됨
  • 번들에 불필요한 초기화 함수 없음, 트리 셰이킹 친화적
  • enum처럼 값→키 역조회가 필요하면 별도 맵 구성 필요

선택 기준

이중 매핑 필요 여부가 1차 기준

  • 값↔키 양방향 매핑과 역조회가 유용한 도메인이면 enum 고려
  • 매핑 방향이 단방향이고 값 집합을 타입으로만 활용하면 as const + 유니온 추출 권장

빌드 환경과 도구 호환성도 중요

  • const enum은 인라인이 보장되는 단일 tsc 파이프라인에서만 안정적
  • 다양한 트랜스파일 단계나 라이브러리 경계를 넘는 경우 as const 대안이 안전

요약

  • enum은 의도 표현과 역조회가 필요한 경우 적합하지만 번들 비용과 트리 셰이킹 한계 존재
  • const enum은 이론상 가장 가벼우나 빌드 파이프라인 제약과 함정으로 실무에서 채택 신중 필요
  • as const는 리터럴 타입 고정과 readonly 부여로 타입 안전성을 높이고, const enum의 주요 사용처를 무리 없이 대체함

마무리

양방향 매핑과 역조회가 반드시 필요하면 enum 선택 그 외 대부분의 상수 집합과 타입 추론 고정 요구에는 as const 기반 패턴 권장 const enum은 빌드 구성과 팀 규칙을 충분히 검토한 뒤 제한적으로 사용 권장

참고자료