TypeScript Enum 대신 Union Type을 사용하는 이유

문제 상황

사용자 권한 관리를 위해 Enum을 사용하고 있었다.

enum UserRole {
  Admin = 'ADMIN',
  Editor = 'EDITOR',
  Viewer = 'VIEWER'
}

function checkPermission(role: UserRole) {
  if (role === UserRole.Admin) {
    // ...
  }
}

빌드 후 번들을 확인했는데, Enum이 IIFE로 변환되면서 불필요한 코드가 추가되는 것을 발견했다. 또한 API 응답으로 받은 문자열을 Enum과 비교할 때 타입 캐스팅이 필요했다.

Union Type으로 전환

const assertion과 Union Type을 조합해서 해결했다.

const USER_ROLES = {
  Admin: 'ADMIN',
  Editor: 'EDITOR',
  Viewer: 'VIEWER'
} as const;

type UserRole = typeof USER_ROLES[keyof typeof USER_ROLES];

function checkPermission(role: UserRole) {
  if (role === 'ADMIN') {
    // ...
  }
}

장점

  1. 런타임 코드 제거: Enum IIFE가 사라지면서 번들 사이즈 감소
  2. 타입 안정성 유지: 'ADMIN' | 'EDITOR' | 'VIEWER'로 정확한 타입 추론
  3. API 연동 간편: 문자열 리터럴이라 타입 캐스팅 불필요
  4. 자동완성: IDE에서 USER_ROLES 객체로 값 참조 가능

const enum을 사용하면 런타임 코드 문제는 해결되지만, 외부 모듈에서 사용할 때 제약이 있어서 Union Type을 선호하게 되었다.

재택근무로 코드 리뷰가 비동기로 진행되다 보니, 이런 작은 개선 사항들을 문서화해두는 게 팀 컨벤션 통일에 도움이 되었다.

TypeScript Enum 대신 Union Type을 사용하는 이유