thumbnail

TypeScript의 Enum, Const Enum, 그리고 as const에 대한 깊은 이해

생성일2023. 10. 31.
태그
작성자지한솔

notion image
오늘은 enumconst enum 그리고 as const에 대해 알아보도록 하겠습니다. 많은 개발자들 사이에서 어떤게 더 좋다, 안좋다 라는 이야기들이 많은데 포스팅을 통해 어떤게 더 좋은지, 어떤게 더 유용한지에 대해 알아보는 시간도 가져보도록 하겠습니다.

Enum (열거형)

TypeScript의 enum은 상수 집합에 이름을 부여하는 방법입니다. enum을 사용하면 코드를 더 명확하게 표현할 수 있으며, 유효한 값들의 집합을 정의할 수 있습니다.

예시 코드

enum Direction { Up, Down, Left, Right } function move(direction: Direction) { // ... } move(Direction.Up); // 유효한 호출 move(10); // 컴파일 에러: 10은 Direction 타입이 아닙니다.

장점

  • 코드 가독성 향상: enum의 사용은 리터럴 값보다 의미를 분명하게 전달합니다.
  • 타입 안정성 강화: enum을 사용함으로써 예상치 못한 값으로 인한 오류를 줄일 수 있습니다.

단점

  • JavaScript로 컴파일 될 때 추가 코드가 생성됩니다. 이는 런타임에 부가적인 비용을 초래할 수 있습니다.

Const Enum (상수 열거형)

const enumenum과 유사하지만, TypeScript 컴파일러에 의해 인라인 처리되어 런타임에서의 추가적인 비용 없이 사용됩니다.

예시 코드

const enum Direction { Up, Down, Left, Right } function move(direction: Direction) { // ... } move(Direction.Up);

장점

  • 런타임 퍼포먼스: 컴파일 시에 enum 멤버가 실제 값으로 대체되어 런타임 비용이 줄어듭니다.

단점

  • 인라인 제약: const enum의 값은 항상 인라인으로 사용되어야 하므로, enum처럼 동적으로 접근할 수 없습니다.
  • 리플렉션의 제한: 런타임에 const enum 멤버들의 리스트를 얻거나 사용하는 것이 불가능합니다.

as const (상수 단언)

as const는 TypeScript에서 리터럴 타입의 값이 변하지 않음을 단언하는 방법입니다. 이를 사용하면 객체 리터럴이나 배열의 모든 프로퍼티를 읽기 전용으로 만들고, 타입을 리터럴 타입으로 좁힐 수 있습니다.

예시 코드

let directions = { up: 0, down: 1, left: 2, right: 3 } as const; function move(direction: typeof directions[keyof typeof directions]) { // ... } move(directions.up); move(10); // 컴파일 에러: 10은 타입 '0 | 1 | 2 | 3'에 할당될 수 없습니다.

장점

  • 유연성: as const를 사용하면 객체 또는 배열이 불변임을 쉽게 선언할 수 있습니다.
  • 타입 추론 강화: TypeScript는 as const를 사용한 변수에 더 구체적인 타입을 추론합니다.

단점

  • 상수값만 가능: 변수에 할당된 값이 상수일 때만 as const를 사용할 수 있습니다.
  • 확장성 제한

Enum vs Const Enum vs as const

Enum

  • 사용 사례: enum은 실행 시점에 객체로 존재해야 할 때, 즉 런타임에 해당 열거형의 키와 값을 모두 사용해야 할 때 적합합니다.
  • 장점: 타입과 값을 모두 가지고 있으며, 런타임에 이를 반영할 수 있습니다. 동적으로 값을 검사하거나 키를 순회할 수 있습니다.
  • 단점: JavaScript로 변환될 때 추가적인 코드가 생성되어 더 큰 번들 사이즈와 런타임 비용을 초래할 수 있습니다.

Const Enum

  • 사용 사례: 런타임에서 열거형의 객체가 필요 없고, 오직 컴파일 타임에서만 상수 값이 필요할 때 const enum이 적합합니다.
  • 장점: 컴파일 시에 인라인 처리되어 런타임 성능에 부담을 주지 않습니다. 번들 사이즈를 줄일 수 있습니다.
  • 단점: 런타임에 열거형의 키와 값을 반영할 수 없습니다. 디버깅이 어려울 수 있고, 타입스크립트 컴파일러 옵션 preserveConstEnums을 설정하지 않으면 해당 정보를 잃어버릴 수 있습니다.

as const

  • 사용 사례: 객체 리터럴이나 배열의 값이 변하지 않으며, 타입 시스템에 리터럴 타입으로서의 최대한의 정보를 제공할 때 as const를 사용합니다.
  • 장점: 불변성을 확보하며, 타입 추론을 통해 더 구체적인 타입을 얻을 수 있습니다. 또한, 코드가 간결해지며 런타임에 추가적인 비용이 발생하지 않습니다.
  • 단점: 확장성이 제한됩니다. 객체 또는 배열의 구조가 변경되면 타입도 함께 변경되어야 하며, 리터럴 타입만을 사용할 수 있어 동적인 키를 가진 객체에는 사용하기 어렵습니다.

어떤 것이 더 나은가?

결국 선택은 사용 사례에 따라 달라집니다:
  1. 런타임 성능이 중요하고, 열거형이 컴파일 타임에만 필요하다면, const enum이 바람직합니다.
  1. 런타임에 열거형의 정보가 필요하다면, enum을 사용해야 합니다.
  1. 객체의 불변성과 타입 추론의 정확성이 중요한 경우에는, as const를 사용하는 것이 좋습니다.
각각의 기능은 특정 상황에서 최상의 결과를 제공하기 위해 설계되었습니다. 따라서 자신의 프로젝트에서 가장 중요한 요소가 무엇인지 고려하고, 그에 맞춰 적절한 기능을 선택해야 합니다.
TypeScript에서 enum을 사용하면 Tree-shaking이 되지 않습니다, 하지만 Union Types을 사용하는 as const의 경우에는 Tree-shaking 이 가능합니다. 이러한 이유때문인지 as const를 사용하자는 여론도 많이 있습니다.
언제나 개발엔 정답은 없고 보다 나은 만 존재한다 생각하기에.. 판단은 스스로가 하는 것이 좋아보입니다!