[TS] enum 제대로 사용하기

장동균·2022년 10월 16일
0

https://blog.logrocket.com/extend-enums-typescript/
해당 글을 번역한 정도 수준에 그치는 글입니다.


상속받아 사용하기

enum MyFavorite {
	Apple = 'apple',
  	Banana = 'banana',
  	Pear = 'pear',
  	StrawBerry = 'strawberry'
}

enum YouFavorite {
	Apple = 'apple',
  	Banana = 'banana',
	Pear = 'pear',
  	Mango = 'mango'
}

enum WeFavorite {
	Apple = 'apple',
  	Banan = 'banana',
  	Pear = 'pear',
  	Orange = 'orange'
}

다음과 같은 enum 3개가 있다고 가정하자. 그렇다면 당연히 우리는 공통적인 부분을 분리하고 싶어진다.

enum Fruit {
	Apple = 'apple',
  	Banana = 'banana',
  	Pear = 'pear'
}

enum MyFavorite extends Fruit {
  	StrawBerry = 'strawberry'
}

enum YouFavorite extends Fruit {
  	Mango = 'mango'
}

enum WeFavorite extends Fruit {
  	Orange = 'orange'
}

type을 상속받을 때 처럼 extends 키워드를 사용한다면 어떨까. 해당 코드는 에러가 발생한다. 타입스크립트에서 enum에 대한 extends 키워드의 사용을 제공하지 않기 때문이다. 더 나아가 타입스크립트는 enum을 상속하거나 받는 언어적 기능을 제공하지 않는다.

첫번째 방법 - type union

enum Door {
  Open = "open",
  Closed = "closed",
  Ajar = "ajar" 
}

enum DoorFrame {
  Missing = "noDoor"
}

type DoorState = Door | DoorFrame; 

let door: DoorState;

door = Door.Ajar
console.log(door) // 'ajar'

door = DoorFrame.Missing
console.log(door) // 'noDoor'

다음 예제처럼 union type을 사용하는 방법이다. 이를 통해 특정 변수의 타입을 여러 개의 enum을 통해 제한할 수 있다. 하지만 이 방법은 단순히 두 개의 enum 타입을 사용하는 방법이다. 두 개 enum을 합친 것의 값을 사용할 수는 없다.

enum Door {
  Open = "open",
  Closed = "closed",
  Ajar = "ajar" 
}

enum DoorFrame {
  Missing = "noDoor"
}

type DoorState = Door | DoorFrame;

DoorState.Open  // Error! DoorState는 타입

두번째 방법 - 스프레드 연산자 사용

enum Move {
  LEFT = 'Left',
  RIGHT = 'Right',
  FORWARD = 'Forward',
  BACKWARD = 'Backward'
}

const myMove = {
  ...Move,
  JUMP: 'Jump'
}

이 방식은 값에 대한 사용이 가능하다. 하지만 좋은 방법은 아니다. Move라는 enum 객체와 myMove라는 객체의 병합이 런타임에서 이루어지기 때문이다. (이전 union type을 사용하는 방식은 컴파일/트랜스파일 타임에서 이루어짐)

결론

보통 enum을 사용할 때 나는 그 값을 사용하는 경우가 훨씬 많은 것 같다. 때문에 첫번째 방법을 사용할 수는 없을 것 같다. 때문에 아예 공통 부분을 분리하려는 노력을 시도하지 않거나 흐린 눈하고 두번째 방법을 사용하는 것이...ㅎ


하나의 enum 안에서 다른 타입을 사용하지 말자

enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = "YES",
}

기술적으로 하나의 enum 내부에 string, number 두 타입의 값이 혼재할 수 있지만 이렇게 사용하는 것은 좋지 않은 방법이다. (enum의 값으로 들어올 수 있는 타입은 string, number 두 가지) (코드 자체에 대한 이해를 어렵게 만들기 때문. 정말로 특별한 이유가 있다면 이런 식의 사용도 가능)


enum을 switch 구문의 조건으로 활용하지 말자

enum DayOfWeek {
  Sunday,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
};

function isItTheWeekend(day: DayOfWeek) {
  switch (day) {
    case DayOfWeek.Sunday:
    case DayOfWeek.Saturday:
      return true;
 
    default:
      return false;
  }
}

개발을 진행하다보면 다음과 같이 enumswitch 구문의 조건으로 활용하는 경우들이 생긴다. 이러한 구문은 다음과 같은 문제들을 가진다.

  1. typescript enum의 특징인 역참조로 인한 문제가 발생할 수 있다.
console.log(isItTheWeekend(DayOfWeek.Monday)); // false

console.log(isItTheWeekend(2)); // false
  1. enum 자체가 수정되는 경우 enum과 함수(isItTheWeekand) 두 곳에서의 수정이 필요해진다.

  2. metadata와 코드의 불필요한 분리다.

해결

const DayOfWeek = {

  Sunday: {
    id: 0,
    apply() { return true }
  },

  Monday: {
    id: 1,
    apply() { return false }
  },
  
  // ...
}

다음과 같이 하나의 객체에서 enum과 함수를 동시에 관리하는 것이 관리의 주체를 줄이는 방법일 수 있다.


참고문헌

https://blog.logrocket.com/extend-enums-typescript/
https://blog.logrocket.com/why-typescript-enums-suck/

profile
프론트 개발자가 되고 싶어요

0개의 댓글