https://medium.com/@seungha_kim_IT/typescript-enum%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-3b3ccd8e5552




TypeScript enum을 사용하는 이유


(본 글은 TypeScript 입문자 중 enum 기능이 있는 다른 언어를 사용해 본 경험이 없는 분들을 위해 쓰여졌습니다. 예제 코드를 TypeScript playground에 붙여 넣고, 마우스 포인터를 변수 위에 둬서 변수의 타입이 어떻게 지정되는지 확인해보세요.)

TypeScript enum은 JavaScript에는 없는 개념으로, 일견 상수, 배열, 혹은 객체와 비슷해보이기도 합니다. 그냥 상수, 배열, 객체를 써도 될 것 같은데, 굳이 enum을 쓰는 이유가 뭘까요?

Enum은 추상화의 수단

다국어 지원을 위해 언어 코드를 저장할 변수를 만들어야 하는 상황을 생각해봅니다.

const code: string = 'en' // string?

제품이 지원할 수 있는 언어는 사전에 정해져있는데, 이 값이 할당될 변수를 string 타입으로 지정하는 것은 범위가 너무 넓은 것 같다는 느낌이 듭니다. 이를 개선해봅시다.

일단은 리터럴 타입과 유니온을 이용해 code 변수에 대한 타입의 범위를 좁혀줄 수 있습니다.

type LanguageCode = 'ko' | 'en' | 'ja' | 'zh' | 'es'const code: LanguageCode = 'ko'

이제 code 변수에 ‘zz’ 같이 이상한 값을 대입하면 컴파일 에러가 납니다. 타입의 범위는 원하는대로 좁혀졌습니다.

하지만 코딩을 하다보니, 제품이 어떤 언어를 지원하기로 했었는지도 가물가물하고, 특정 국가 코드가 정확히 어떤 언어를 가리키는지 일일이 외우기도 쉽지 않습니다. 이 때 상수를 여러 개 둬서 문제를 해결할 수는 있지만, 그닥 깔끔한 느낌은 아닙니다.

const korean = 'ko'
const english = 'en'
const japanese = 'ja'
const chinese = 'zh'
const spanish = 'es'
// 이렇게 하면 언어 코드가 위아래에 중복되고
type LanguageCode = 'ko' | 'en' | 'ja' | 'zh' | 'es'
// 이렇게 하면 코드가 너무 길어집니다
// type LanguageCode = typeof korean | typeof english | typeof japanese | typeof chinese | typeof spanish
const code: LanguageCode = korean

이런 경우에 enum을 사용해 리터럴의 타입과 값에 이름을 붙여서 코드의 가독성을 크게 높일 수 있습니다.

export enum LanguageCode {
korean = 'ko',
english = 'en',
japanese = 'ja',
chinese = 'zh',
spanish = 'es',
}
// 여기서
// LanguageCode.korean === 'ko'
// (의미상) LanguageCode === 'ko' | 'en' | 'ja' | 'zh' | 'es'
const code: LanguageCode = LanguageCode.korean

짧은 코드로 타입의 범위도 좁히고, 가독성도 높일 수 있게 되었습니다.

enum은 객체

TypeScript enum은 그 자체로 객체이기도 합니다.

const keys = Object.keys(LanguageCode) // ['korean', 'english', ...]const values = Object.values(LanguageCode) // ['ko', 'en', ...]

그렇다면 그냥 객체를 사용하는 것과는 어떤 차이점이 있을까요?

1. 객체는 (별다른 처리를 해주지 않았다면) 속성을 자유로이 변경할 수 있는데 반해, enum의 속성은 변경할 수 없습니다.

2. 객체의 속성은 (별다른 처리를 해주지 않았다면) 리터럴의 타입이 아니라 그보다 넓은 타입으로 타입 추론이 이루어집니다. enum은 항상 리터럴 타입이 사용됩니다.

3. 객체의 속성 값으로는 JavaScript가 허용하는 모든 값이 올 수 있지만, enum의 속성 값으로는 문자열 또는 숫자만 허용됩니다.

정리하자면, 같은 ‘종류’를 나타내는 여러 개의 숫자 혹은 문자열을 다뤄야 하는데, 각각 적당한 이름을 붙여서 코드의 가독성을 높이고 싶다면 enum을 사용하세요. 그 외의 경우 상수, 배열, 객체 등을 사용하시면 됩니다.

ps. 다만, 객체 리터럴에 대해 상수 단언(const assertion)을 해준다면 이 객체를 enum과 비슷한 방식으로 사용할 수 있습니다. 상수 단언에 대해서는 제가 쓴 다른 글도 참고해주세요.

const languageCodes = {
korean: 'ko',
english: 'en',
japanese: 'ja',
chinese: 'zh',
spanish: 'es',
} as const // const assertion
// 속성 값을 변경할 수 없음
// 속성의 타입으로 리터럴 타입이 지정됨
type LanguageCode = typeof languageCodes[keyof typeof languageCodes]const code: LanguageCode = languageCodes.korean

ps. TypeScript에는 enum의 속성 값을 명시적으로 지정해주지 않아도 자동으로 0부터 시작하는 정수들이 지정되는 기능이 있습니다. 한 번 검색해보세요.

'frameworks > typescript' 카테고리의 다른 글

TypeScript 핸드북 1 - 기본 타입  (0) 2019.04.24
tsconfig 컴파일 옵션 정리  (0) 2019.04.05
interface와 class의 상속관계 증명  (0) 2019.02.07
[typescript]decorator  (0) 2018.12.11
[typescript]iterator  (0) 2018.12.11

+ Recent posts