enum을 사용하고 계신가요?

sujin·2025년 2월 24일
0
post-thumbnail

타입스크립트를 사용해보셨다면 enum에 대해서 한번쯤 사용해 보셨을텐데요. 혹시 "enum 사용을 지양해야한다" 는 말을 들어보신 적이 있으신가요? 저는 예전 면접에서 처음 들었었는데요. 혹시 저처럼 처음들어 보시는 분들을 위해 enum 사용을 왜 조심히 해야하는 것인지에 대해 정리해 보려고 합니다.



1️⃣ enum 이란?

enum은 열거형(enumeration)의 줄임말로, 연관된 상수들을 하나의 그룹으로 묶어 표현하는 TypeScript의 기능입니다. 이를 통해 코드의 가독성과 유지보수성을 높일 수 있습니다.

const user1 = {
	name: "철수",
	role: 0 
}

const user2 = {
	name: "영희",
	role: 1 
}

const user3 = {
	name: "민수",
	role: 2
}

위의 예시처럼 역할에 숫자 값을 부여했을 때 0,1,2만 보고 어떤 의미인지 바로 알기가 어렵습니다. 이런 경우 enum을 통해 개선할 수 있습니다.

enum Role {
	ADMIN = 0,
	USER = 1,
	GUEST = 2
}

const user1 = {
	name: "철수",
	role: Role.ADMIN 
}

const user2 = {
	name: "영희",
	role: Role.USER  
}

const user3 = {
	name: "민수",
	role: Role.GUEST 
}

enum을 활용하여 역할을 정의하고 그 의미를 명확하게 할 수 있습니다. 또한, 0 대신 Role.ADMIN 을 사용함으로써 코드의 가독성을 올릴 수 있으며 오타도 방지할 수 있습니다.

enum의 자동 할당

enum은 값을 명시적으로 할당하지 않으면 자동으로 0부터 시작해서 순차적으로 값을 할당합니다.

enum Role {
	ADMIN,  // 0
	USER,   // 1
	GUEST   // 2
}

또한, 특정 값에서 시작하도록 지정할 수도 있습니다.

enum Role {
	ADMIN = 9,  // 9
	USER = 10,  // 10
	GUEST       // 11
}

enum과 union의 차이점

  • enum은 연관된 상수들을 하나의 그룹을 묶어 관리합니다.
    	enum Role {
    			ADMIN = 0,
    			USER = 1,
    			GUEST = 2
    		}
  • union은 특정 변수나 속성이 여러 개의 정해진 값 중 하나를 가집니다.
     type Role = "ADMIN" | "USER" | "GUEST";
  • 즉, enum은 하나의 객체처럼 동작하며 특정 값에 접근할 수 잇지만 union은 값들의 집합을 나타내는 타입이며 값들의 범위를 제한하는 역할을 합니다.

2️⃣ enum 의 취약점

위 처럼 enum은 편리한 기능을 제공하지만, 몇 가지 단점이 존재합니다.

불필요한 런타임 코드 생성

enum은 컴파일된 Javascript 코드에서 객체로 변환되어 추가적인 코드가 생성됩니다.

ASIS

TOBE

이러한 추가 코드는 번들 크기를 증가시키고 최적화에 불리할 수 있습니다.

Three Shaking의 어려움

Three Shaking사용하지 않는 코드를 제거하여 번들 크기를 줄이는 최적화 기법입니다. 그러나 enum은 실제로 런타임에 객체로 변환되기 때문에 이를 잘라내기 어렵습니다.

enum의 값은 컴파일된 후 객체 형태로 존재하고, 해당 객체를 참조하는 코드가 존재할 수 있기 때문에, tree shaking이 제대로 동작하지 않습니다. 이로 인해 사용하지 않는 enum 값들이 최종 번들에 포함되어 최적화가 어려워집니다.

타입 안정성 문제

enum은 숫자 값을 기본으로 하기 때문에, 역방향 매핑 을 지원합니다. 따라서 의도치 않은 값이 할당되는 문제가 발생할 수 있습니다.

enum Status {
  Loading,
  Success,
  Error,
}

let statusName: string = Status[1]; // "Success"
let statusIndex: number = Status["Success"]; // 1

3️⃣ 그렇다면 어떻게 사용해야 할까?

as const

타입스크립트 공식 문서에서는 enum 대신 as const 사용을 지향하고 있습니다.

as const 는 TypeScript에서 객체나 배열을 리터럴 타입으로 고정할 수 있게 해줍니다.

리터럴 타입이란?
변경 불가능한 값을 나타내는 타입입니다. 예를 들어, "loading", "success", "error" 같은 값을 리터럴 타입으로 지정하면, 해당 값만 허용되고 다른 값은 타입 오류가 발생합니다. 이를 통해 값의 범위를 제한하고 예상치 못한 값을 방지 할 수 있습니다.

따라서, as const 를 사용하면 값이 변경되지 않도록 고정되고, 타입은 해당 값에 정확히 맞춰지기 때문에 의도치 않은 값 할당을 방지할 수 있습니다.

const Status = {
  Loading: "loading",
  Success: "success",
  Error: "error",
} as const;

type Status = typeof Status[keyof typeof Status];

let status: Status = "loading"; // 정상
status = "completed"; // 에러 발생

위 예시에서 Status는 as const 로 리터럴 타입으로 고정되었고, 그 결과 Status 타입은 "loading", "success", "error"로 제한됩니다. 이렇게 하면 원하는 기능을 사용하면서 enum에서 발생할 수 있는 여러 문제들을 피할 수 있게 됩니다!

profile
개발댕발

1개의 댓글

comment-user-thumbnail
2025년 2월 25일

좋은 글 감사합니다 !

답글 달기

관련 채용 정보