typescript 에서 enum 사용에 관한 질문 모음

Q&A 큐레이션

1. [TS] 백엔드에서는 enum 써도 되나요?

타입스크립트에서 enum 쓰지 않아야 하는 이유가 IIFE로 변환되서 트리 쉐이킹이 잘 안 된다는 이유인 걸로 알고있는데 그럼 백엔드에서는 써도 되나요?


답변

안녕하세요. enum의 사용유무는 백엔드/프론트엔드의 관점에서 보는것보단 각 언어의 특성에 따른 enum사용유무로 접근하셔야 이해하시기가 편할것 같아요. 프론트엔드의 업무를 전문적으로 맡아본것이 아니여서 가볍게 구글링해봤을때는 Tree-shaking이라는 import되지 않는 함수를 지우는 최적화 대상에서 제외되기 때문이 권장하지 않는다고 했습니다. 자바에서는 enum사용을 적극 권장합니다. 첫째 이유로는 enum은 불변(immutable) 불변의 중요성은 데이터의 정합성을 지키는것에 있죠. 두번째로는 자바의 상수(final 자바스크립트는 const)의 사용보다는 가독성 측면으로도 enum사용을 권장하고 있습니다. 아래의 코드예시를 보면 간단하게나마 이해가 편하실 꺼에요. 남자(MAN) 여자(WOMAN)의 구분을 상수로 사용할 경우에는 타입안정성을 보장할 수 없고, 만약 MAN의 값이 02로 바뀔경우 의도치않은 결과가 나올 수 있습니다. 자바에서는 이러한 이유로 enum을 권장하고있고 python과 c에도 enum을 지원하고있지만 자바와는 또다른 구조입니다. 차이중 하나는 java에는 enum에 메서드나 속성을 가질수 있지만 c의 enum은 순수한 정수값일뿐 메서드나 속성을 가질수 없다고합니다. 답변이 참고가 되셨으면 좋겠네요 :)

이 질문 바로 가기

2. typescript enum은 지양해야하나요?

프로젝트 진행 중에 typescript enum 관련해서 팀원들과 의견이 갈려서 질문드립니다. 우선 기존 코드부터 설명드리면, enum Categories { Value, Value2, Value3 } 와 같은 형태가 있고 또 const categoryDataMap = { [Categories.Value]: { name: "카테고리1", }, [Categories.Value2]: { name: "카테고리2", }, [Categories.Value3]: { name: "카테고리3", } } const getCategoryDataByCategory = (category: Categories) => { return categoryDataMap[category] } 와 같은 mapper 오브젝트와 유틸 함수도 존재합니다. 저는 typescript 관련 공부를 했을때 enum 보다는 object as const를 사용하라고 배웠었는데요. 예를 들면 위의 코드를 const Categories = { 1: { name: "카테고리1" }, 2: { name: "카테고리2" }, 3: { name: "카테고리3" } } as const type CategoryKeys = keyof typeof Categories; const getCategoryDataByCategory = (category: CategoryKeys) => { return Categories[category] } 이렇게 바꿔줄수 있는데요. 저는 이 방법이 getCategoryDataByCategory를 사용했을때 category 인자의 타입이나 해당 함수가 리턴하는 타입이 더 명시적으로 나와서 편하다고 느꼈었습니다. 하지만, 팀원들은 다른 견해를 가지고 있었어요. 굳이 enum을 저렇게 바꿔야하는가? 라는 의문을 제기해주셨는데요. ---- 저도 typescript enum을 지양해야한다라고 어렴풋이 알고 있어서 "왜 굳이 enum인 친구들을 더 가독성이 떨어지는 후자의 방법으로 바꿔야하지"라는 궁금증이 생겨서 여쭤봅니다. 흔히 얘기하시는 enum 사용시 발생하는 treeshaking 문제는 enum을 cont enum으로 선언해주면 어느정도 해결되는 것 같은데, 굳이 const 형태로 바꿔줘야하는 이유가 있을까요? typescript에서 enum을 지양하라는 맥락에 대해 좀 더 구체적인 이유를 알고 싶습니다. 긴글 봐주셔서 감사합니다


답변

사실 많은 프로그래밍 언어에서 열거형을 사용하고 해당 문법으로 생산성이 증가하는데요. 하지만 Typescript의 열거형은 몇 가지 문제를 지니고 있습니다. 바로 예상과 다르게 동작하는 부분들이 있는데요! 1. 숫자형 enum의 경우 파라미터로 enum Something { A, B, C, D }를 해놓고 something(parameter: Something) 함수에 파라미터로 0,1,2,3 외에 다른 숫자를 집어넣어도 컴파일 시 에러가 나지 않습니다. 2. 문자형 enum의 경우 TS는 구조적 타이핑을 사용하는데 다른 타입과는 달리 enum의 경우는 명목적 타이핑을 사용합니다. 따라서, enum Something1 { A = 'A' }, enum Something2 { A = 'A' }에서 Something1.A === Something2.A 값은 실제로 같은 문자열임에도 불구하고 false입니다. TS를 빡빡하게 쓰신다면 애초에 겹칠 수 없는 값이라고 에디터나 IDE에서 안내할 것입니다. (Something1과 Something2가 객체라면 그러지 않았겠죠?) 이와 같이 TS에서 enum 동작은 예상과 달리 동작하는 부분들이 있긴 합니다. 질문에 작성하신 getCategoryDataByCategory의 파라미터 타입을 enum으로 하면 위에 말씀드린대로 음수나 1000 이런 값이 나와도 컴파일 시 오류를 거르지 못하니까요! 그러니 작성자분께서 뒤에 작성하신 코드가 아무래도 더 type safe하고 런타임에도 문제가 없을 코드이긴 합니다. 하지만 그럼에도 불구하고 저도.. enum을 잘 애용하고 있긴 합니다..ㅎ 아무래도 간결한 코드와 타입체크 그리고 생산성에 있어 쓰고 있는 것 같습니다. 질문하신대로 enum을 쓰지 않은 코드를 살펴보면 가독성이 떨어지긴 하니까요 ㅎㅎ TS에서 enum 논쟁은 언제나 끝이 없는거 같네요..! + 아 추가로 덧붙이자면 enum도 요샌 트리세이킹 문제가 항상 생기진 않는거 같더라구요..?

외 2개 답변 보러 가기

3. 타입스크립트 keyof typeof 는 뭔가요?

안녕하세요 코드를 보다가 type PackageTypes = keyof typeof Package; 라는 코드를 봤는데 여기서 keyof typeof는 뭔가요? PacakgeTypes에 마우스를 올려보면 "curated" | "drafted" | "single" 이런식으로 나오는데 뭔지 잘 모르겠네요.


답변

하나씩 풀어서보면 이해하시기 쉬울 것 같습니다. keyof typeof Package 일단 keyof 부터 보시면 object의 키 값을 읽어온다고 합니다. (https://www.typescriptlang.org/docs/handbook/2/keyof-types.html) 다음 typeof 는 해당 변수의 type을 뜻한다고 합니다. (https://www.typescriptlang.org/docs/handbook/2/typeof-types.html) 마지막 Package는 정보가 없지만 아마도 "curated", "drafted", "single"이라는 정보를 담고 있는 enum 이겠죠? enum Package { curated, drafted, single } 와 같은 형태로 선언됐을거라고 생각합니다. 다시 keyof typeof Package를 보시면 "Package의 타입의 키"를 뜻한다는 것을 알 수 있게 됩니다. 한가지 더 첨언하자면, enum이라고 추측한 이유는 타입스크립트 enum에 keyof를 사용하면 그냥 객체 형태에 사용하는 것처럼 동작하지 않는다고 공식 문서에 나와있습니다. enum의 키 값을 읽어오는 예시로 keyof typeof를 쓰고 있는 것을 알 수 있습니다. (https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-compile-time)

이 질문 바로 가기

4. 라라벨 enum 타입 havingRaw절 사용방법 도와주세요ㅠㅠ

안녕하세요 :) 현재 라라벨로 프로젝트를 하고있습니다. havingRaw을 사용하는데 다른 타입들의 데이터들은 다 잘 작동하는데 데이터타입이 enum인 것만 작동을 안합니다. 그러나 아래의 sql문은 하이디sql 에서 실행이 잘 됩니다. SELECT order_id AS cnt FROM test_table WHERE mall_id = 'test_mall' AND user_id = 'test_user' GROUP BY order_id HAVING MIN(type) = 'p' 데이터 타입은 아래와 같습니다. order_id = varchar mall_id = varchar user_id = varchar type = enum $row= DB::table("test_table") ->select(DB::raw('order_id as cnt')) ->where("mall_id", $test_mall) ->where("user_id", $test_user) ->groupBy('order_id') ->havingRaw('MIN(type) = p') ->get(); 해당 쿼리빌더에 잘못된 점이 있을까요??


답변

해당 sql에 대한 리턴값이 로그에 출력되었을텐데 해당 내용은 없나요? 라라벨을 잘몰라서 답변달기에 조심스럽지만 sql 자체가 문제가 없지만 프레임워크에서 돌때 에러가 났다면 프레임워크에서 빌드한 쿼리가 위의 SQL과 다를 것이라 예상이 됩니다. havingRaw('MIN(type) = p') <- 위 쿼리에서는 MIN(type) = 'p' 의 형태인데 혹시 'MIN(type) = p' <- 이부분이 MIN(type) = p 이렇게 빌드된게 아닐까요?

이 질문 바로 가기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!