타입스크립트 Enum은 해롭다

오늘은 조금 조심스러운 주제입니다. "타입스크립트의 Enum을 써도 괜찮은가?"에 대해서 개발자들 사이에서 논쟁이 있었습니다. 이에 대해 "타입스크립트 enum은 해롭다"고 주장하는 타입스크립트 유튜버의 영상을 가져왔습니다. 이런 류(XXX is bad)의 제목을 좋아하지는 않지만 흥미로운 주제거리인 것 같아서 여러분도 한 번 고민해보시면 좋을 것 같습니다. 영상의 주장과 부연 설명을 덧붙여서 정리해봤습니다. 1. Enum은 런타임에 예측할 수 없게 동작한다. 타입스크립트가 타입 기능만 발전시킨다는 원칙을 세우기 전에 타입 공간과 값 공간의 경계를 혼란스럽게 만드는 몇 가지 기능이 있었는데 그 중 하나가 Enum입니다. 타입스크립트 스터디 책으로 유명한 <이펙티브 타입스크립트>는 "자바스크립트와 타입스크립트에서 동작이 다르기 때문에 문자열 열거형은 사용하지 않는 것이 좋습니다. 열거형 대신 리터럴 타입의 유니온을 사용하면 됩니다."라고 얘기합니다. 예측할 수 없는 동작은 버그를 찾아내기 어렵게 만드는데, 이는 버그를 더 잘 찾기 위해 타입스크립트를 사용하는 목적과 상반됩니다. 2. Enum은 구조적 타이핑이 아닌 명목적 타이핑(nominally typing)을 사용하여 타입스크립트의 규칙을 깨뜨린다. 명목적 타이핑을 사용하기 때문에 아래와 같이 함수를 호출하면 타입 에러가 발생합니다. ``` enum LogLevel {  DEBUG = 'DEBUG',  WARNING = 'WARNING',  ERROR = 'ERROR' } function log(message: string, level: LogLevel) {  // ... } log('HEY', 'DEBUG')     //~~~~~~ 'DEBUG' 타입은 'LogLevel' 타입에 할당할 수 없습니다. ``` 이 에러를 고치려면 해당 enum을 직접 불러와서 LogLevel.DEBUG 와 같이 사용해야 합니다.화자는 이런 동작이 타입스크립트의 룰을 깨뜨리는 행위라고 비판합니다. 3. Enum 대신에 자바스크립트의 Plain Object를 쓰거나 Union 타입으로 Enum을 대체하는 것을 권장한다. ``` const LOG_LEVEL = {  DEBUG = 'DEBUG',  WARNING = 'WARNING',  ERROR = 'ERROR' } as const; // 또는 union을 사용 type LogLevel = 'DEBUG' | 'WARNING' | 'ERROR'; ``` 화자는 이렇게 사용하는 것이 더 간단하고, 자연스러우며, 대부분의 오픈소스 앱에서도 사용하는 방식이라고 얘기합니다. 이렇게 하면 번거로운 import가 필요하지 않으며, 런타임 영역과 타입 영역의 경계를 유지할 수 있습니다. 그 외에도 Enum이 번들러의 Tree Shaking을 방해하는 원인이라는 의견, 객체로 정의했을 때 더 쉽게 루프돌 수 있어서 낫다는 의견, 숫자형 enum이 타입 세이프하지 않다는 의견도 있었습니다. 이에 반발하는 의견도 많았습니다. "실제로 Enum을 프로젝트에 적용하는 동안 어떤 문제도 일어나지 않았으며 가독성과 엄격함에 대한 장점이 있다." "오히려 명목적 타이핑이 엄격한 타입 체크에 도움이 된다. 예를 들어 LogLevel.DEBUG와 ReportLevel.DEBUG는 같지만 다르다. 우리는 값이 아닌 Enum이 무엇을 나타내는지에 대해 관심을 두어야 한다." 개인적인 의견으로는 타입스크립트는 타입을 안전하게 사용하기 위한 보조 도구로 쓰여야하며, 그 이상의 역할을 맡기는 건 예측하지 못한 동작을 일으킬수도 있어서 좋지 않은 것 같습니다. (그렇다고 잘 쓰고 있는 프로젝트에 굳이 제거할 정도는 아니지만요) 내 팀, 내 프로젝트에 어떤 것이 더 적합한지 고민해보고 결정해보면 좋을 것 같습니다.

Enums considered harmful

YouTube

Enums considered harmful

다음 내용이 궁금하다면?

또는

이미 회원이신가요?

2022년 12월 20일 오전 10:32

댓글 2