앱을 개발하다보면 상수를 선언해야할 때가 있다.
예를 들어 카드결제와 관련한 앱을 만든다고 생각해보자.
카드 식별을 할 때 각 은행별로 할당된 코드 code로 식별한다고 생각하자.
1. as const로 상수와 타입 선언하기
as const
키워드를 이용해 은행 코드를 상수로 선언할 수 있다
export const BankCodeList = {
BCCard: '361',
ShinHanCard: '366',
KakaoBank: '090',
HyunDaiCard: '367',
} as const;
그러면 BankCodeList
의 value들에 해당하는 은행 코드 타입은 typeof
, keyof
키워드를 이용해 선언할 수 있다.
export type BankCode = (typeof BankCodeList)[keyof typeof BankCodeList];
// BankCode '361' | '366' | '090' | '367'
또한 은행 코드와 카드 이름을 매핑하는 상수도 만들 수 있을 것이다.
export const CardName = {
[BankCodeList.BCCard]: 'BC카드',
[BankCodeList.ShinHanCard]: '신한카드',
[BankCodeList.KakaoBank]: '카카오뱅크',
[BankCodeList.HyunDaiCard]: '현대카드',
} as const;
2. enum으로 상수와 타입 선언하기
as const
를 이용해 상수를 선언할 수도 있지만, 위 예제와 같이 string
타입의 상수를 선언하는 경우엔 enum
을 고려할 수도 있다.
자바스크립트에는 없고 타입스크립트가 제공하는 enum
에 대한 자세한 내용은 각자 공식문서를 참고해보고, 먼저 코드를 통해 핵심만 알아보자.
위에서 선언한 BankCodeList
객체와 BankCode
타입을 enum
을 이용하면 다음과 같이 선언할 수 있다.
// string enum
export enum BankCode {
BCCard = '361',
ShinHanCard = '366',
KakaoBank = '090',
HyunDaiCard = '367',
}
// enum은 타입, 값으로 사용할 수 있다.
const BCCardCode:BankCode.BCCard = BankCode.BCCard;
console.log(BCCardCode); // '361'
const backCode: BankCode = BankCode.KakaoBank; // BankCode.[key] 전부 할당 가능
엥? 타입 선언은 어디갔는지 의문을 가질 수 있다.
실제로 enum
은 그 자체를 타입으로 사용할 수 있고, BankCode.BCCard
와 같이 런타임때 value로도 접근할 수 있다.
이렇게 string enum을 쓰면 타입선언을 위해 keyof
typeof
같은 문법을 안쓰고 상수 선언과 동시에 타입까지 선언할 수 있다.
즉 타이핑이 줄어들어서 편리하다.
또한 enum
은 사용처에서 리터럴이 아니라 enum
상수를 import
해서 사용하도록 강제하는데, 이는 개발자의 오타를 방지하는 효과도 있다.
부록: number enum
enum
객체 내부 value의 값이 number
인 number enum의 경우 reverse mapping이라고 해서 컴파일이 특이하게 된다.
// number enum
export enum BankCode {
BCCard = 361,
ShinHanCard = 366,
KakaoBank = 90,
HyunDaiCard = 367,
}
// js 컴파일 시
export var BankCode;
(function (BankCode) {
BankCode[BankCode["BCCard"] = 361] = "BCCard";
BankCode[BankCode["ShinHanCard"] = 366] = "ShinHanCard";
BankCode[BankCode["KakaoBank"] = 90] = "KakaoBank";
BankCode[BankCode["HyunDaiCard"] = 367] = "HyunDaiCard";
})(BankCode || (BankCode = {}));
// reverse mapping으로 인해 값으로 키에 접근할 수 있다.
console.log(BankCode[BankCode.BCCard]) // BCCard
console.log(BankCode[361]) // BCCard
// reverse mapping으로 인해 Object.keys로 접근할 시 value까지 key값으로 들어간다.
console.log(Object.keys(BankCode)); // ["90", "361", "366", "367", "BCCard", "ShinHanCard", "KakaoBank", "HyunDaiCard"]
reverse mapping 때문에 사용할 때 혼란이 올 수 있고, 버그가 생길 수 있기 때문에 number enum의 사용은 추천하지 않는다.
즉 number타입의 상수가 필요할때는 enum을 지양하자.
부록2: tree shaking
enum
사용을 고려할 때, tree shaking
도 고려대상이다.
Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. – webpack doc
위 설명과 같이 tree shaking은 코드로 작성은 되어 있지만 런타임때 사용하지 않는 코드를 번들링 시 제거하는 기법이다.
따라서 번들 사이즈를 줄일 수 있다.
많은 포스팅에서 enum은 tree shaking이 안된다는 이유로 사용을 꺼린다고 하는데.. 직접 검증해보았다.
검증 방식은 enum
을 import
는 하지만 직접 사용을 하지않는 경우를 코드로 작성했다.
Webpack
"webpack": "^5.86.0" 기준 enum
은 treeshaking
이 된다.
Rollup
“Rollup”: “3.25.1” 기준 enum
은 treeshaking
이 되지 않는다.
vite
해당 글에서 vite
도 enum
treeshaking
이 된다고 한다.
즉 번들러에 따라 enum tree-shaking 여부가 달라진다.
사실.. enum을 선언해서 사용하지 않는 일이 얼마나 될까?
또 번들링 사이즈를 불가피하게 극한으로 줄여야하는 상황이 아니라면 enum 선언 정도의 크기는 무시해도 괜찮지 않을까..라는 개인적인 의견이다.
마무리
타입스크립트에서 상수를 선언할 때는 as const
나 enum
을 사용할 수 있다.
number enum의 경우 reverse mapping이 일어나기 때문에 양방향 매핑이 꼭 필요한 경우가 아니라면 사용을 추천하지 않는다.
필요하다면 동작을 확실히 알고 사용하자
string 상수를 선언할 때는 enum을 고려해볼만 하다.
Reference
https://www.kabuku.co.jp/developers/good-bye-typescript-enum
https://techblog.woowahan.com/9804/#toc-3
https://xpectation.tistory.com/218
https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#all-enums-are-union-enums
TS playground
'프론트엔드' 카테고리의 다른 글
[번들 사이즈 최적화] 웹팩으로 생성한 번들 파일을 분석해보자(BundleAnalyzerPlugin) (0) | 2023.09.11 |
---|---|
회원가입 폼에서 주로 쓰이는 필수입력사항에* 별표 표시하기 (0) | 2023.07.16 |
KDC 한국십진분류표 (0) | 2023.06.21 |
styled-components를 이용할 때 기존 태그의 attributes를 override하는법 (0) | 2023.06.20 |
컴포넌트를 만들 때 기존 태그의 props를 상속받는 법 (0) | 2023.06.17 |