💻 프로그래밍

Enum

열거형

명명된 상수 집합을 정의하는 타입. 코드 가독성과 안전성 향상.

📖 상세 설명

Enum(열거형, Enumeration)은 관련된 상수들의 집합을 하나의 타입으로 정의하는 프로그래밍 구조입니다. 1970년대 Pascal 언어에서 처음 도입되었으며, 현재는 Java, C#, TypeScript, Python, Rust 등 대부분의 현대 프로그래밍 언어에서 지원합니다.

Enum의 핵심 목적은 매직 넘버(magic number)나 문자열 리터럴 대신 의미 있는 이름을 사용하여 코드의 가독성을 높이는 것입니다. 예를 들어 상태 코드 0, 1, 2 대신 Status.PENDING, Status.APPROVED, Status.REJECTED처럼 명확한 이름을 사용하면 코드 의도가 한눈에 파악됩니다.

Enum은 컴파일 타임에 타입 검사가 이루어지므로 잘못된 값이 들어오는 것을 사전에 방지합니다. IDE의 자동완성 기능도 활용할 수 있어 개발 생산성이 향상되고, 리팩토링 시에도 참조 위치를 쉽게 추적할 수 있습니다.

실무에서 Enum은 상태(Status), 역할(Role), 권한(Permission), 방향(Direction), 요일(DayOfWeek) 등 고정된 선택지가 있는 모든 곳에서 활용됩니다. 특히 API 응답 코드, 데이터베이스 상태 필드, 설정 옵션 등에서 문자열보다 Enum을 사용하면 오타로 인한 버그를 원천 차단할 수 있습니다.

💻 코드 예제

// 1. TypeScript - 숫자형 Enum
enum OrderStatus {
    PENDING = 0,      // 대기중
    CONFIRMED = 1,    // 확인됨
    SHIPPED = 2,      // 배송중
    DELIVERED = 3,    // 배송완료
    CANCELLED = 4     // 취소됨
}

// 2. TypeScript - 문자열 Enum (권장)
enum UserRole {
    ADMIN = 'ADMIN',
    MANAGER = 'MANAGER',
    USER = 'USER',
    GUEST = 'GUEST'
}

// 3. Enum 사용 예시
interface User {
    id: number;
    name: string;
    role: UserRole;
}

function checkPermission(user: User): boolean {
    // switch문과 함께 사용하면 모든 케이스 처리 보장
    switch (user.role) {
        case UserRole.ADMIN:
            return true;
        case UserRole.MANAGER:
            return true;
        case UserRole.USER:
            return false;
        case UserRole.GUEST:
            return false;
        default:
            // 새 역할 추가 시 컴파일 에러로 누락 방지
            const _exhaustive: never = user.role;
            return false;
    }
}

// 4. Python Enum 예시
// from enum import Enum, auto
//
// class Color(Enum):
//     RED = auto()      # 1
//     GREEN = auto()    # 2
//     BLUE = auto()     # 3
//
// def get_hex_code(color: Color) -> str:
//     mapping = {
//         Color.RED: '#FF0000',
//         Color.GREEN: '#00FF00',
//         Color.BLUE: '#0000FF'
//     }
//     return mapping[color]

// 5. 실제 API 응답에서의 활용
const order = {
    id: 12345,
    status: OrderStatus.SHIPPED,
    createdAt: new Date()
};

console.log(`주문 상태: ${OrderStatus[order.status]}`); // "주문 상태: SHIPPED"
console.log(`상태 코드: ${order.status}`);              // "상태 코드: 2"

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"결제 상태를 문자열로 관리하다 보니 오타 버그가 자주 발생합니다. PaymentStatus Enum으로 리팩토링하면 타입 안전성도 확보하고 IDE 자동완성도 활용할 수 있어요."
💬 면접에서
"Enum을 사용하면 컴파일 타임에 유효하지 않은 값을 잡아낼 수 있어서 런타임 에러를 줄일 수 있습니다. TypeScript에서는 문자열 Enum을 권장하는데, 디버깅 시 값을 바로 확인할 수 있고 리버스 매핑 문제도 없기 때문입니다."
💬 코드 리뷰에서
"여기서 status === 'pending' 대신 status === OrderStatus.PENDING으로 바꿔주세요. 문자열 리터럴은 오타가 나도 에러가 안 나지만 Enum은 잘못 입력하면 바로 컴파일 에러가 발생해서 안전합니다."

⚠️ 흔한 실수 & 주의사항

숫자 Enum의 리버스 매핑 문제

TypeScript 숫자 Enum은 값에서 이름으로의 리버스 매핑이 생성되어 Object.keys()나 Object.values() 결과가 예상과 다를 수 있습니다. 문자열 Enum을 사용하거나 const enum을 활용하세요.

Enum 값 변경 시 데이터 마이그레이션

데이터베이스에 숫자형 Enum 값을 저장했다면 Enum 순서를 변경하면 기존 데이터 의미가 달라집니다. 문자열 Enum을 사용하거나 명시적으로 값을 지정하세요.

const enum으로 번들 크기 최적화

TypeScript에서 const enum을 사용하면 컴파일 시 인라인으로 치환되어 런타임 오버헤드가 없어집니다. 단, isolatedModules 옵션이나 declaration 파일에서는 주의가 필요합니다.

🔗 관련 용어

📚 더 배우기