Engineering/TIL
enum 대체하기 (부제 : enum은 나쁘다 적어도 TS에서는)
rudy K
2024. 1. 14. 23:37
enum을 대체해야하는 이유
1. enum은 어렵게 트랜스파일된다
typescript
enum Player {
Rudy,
David,
Jay
}
javascript (transpiled)
"use strict";
var Player;
(function (Player) {
Player[Player["Rudy"] = 0] = "Rudy";
Player[Player["David"] = 1] = "David";
Player[Player["Jay"] = 2] = "Jay";
})(Player || (Player = {}));
문제점
- 디버깅이 어렵다
- tree-shaking이 불가능하다
- enum은 JS에서 즉시함수로 트랜스파일된다
- 번들러는 이 코드가 사용되는지 알 수가 없다
- 냅다 번들에 포함 -> 뚱뚱한 번들 완성
2. (당연하게도) enum의 기본타입은 숫자이다
enum Player {
Rudy,
David,
Jay
}
console.log(Player.Rudy) // 0
문제점
- 디버깅이 어렵다
3. enum은 literal 타입추론이 불가능하다
enum Player {
Rudy = 'rudy',
David = 'david',
Jay = 'jay'
}
const player: Player = 'Rudy' // TS error
// Type '"Rudy"' is not assignable to type 'Player'.(2322)
4. enum은 안전하지않다
4-1) 같은 이름의 enum은 합쳐진다
enum Player {
Rudy = 'rudy',
David = 'david'
}
enum Player {
Jay = 'jay'
}
console.log(Player.Rudy, Player.Jay) // rudy, jay
4-2) value는 같고 key는 다르면 이상한 결과가 나온다
enum NumberName {
One = 1,
TWO = 2,
}
enum Player {
THREE = 1
}
console.log(Player[1]) // THREE
5. enum의 number 타입에러 (TS < 5.x.x)
enum NumberName {
ONE = 1,
TWO = 2,
THREE = 3
}
const hundred: NumberName = 100 // no error
enum을 대체하는 방법
1. const enum
사용 전
- typescript
const enum Player {
Rudy = 'rudy',
David = 'daivd',
Jay = 'jay'
}
- javascript (transpiled)
"use strict";
사용시점
- typesciprt
const enum Player {
Rudy = 'rudy',
David = 'daivd',
Jay = 'jay'
}
const player: Player = Player.Rudy
- javascript (transpiled)
"use strict";
const player = "rudy" /* Player.Rudy */;
- const enum은 사용시점에만 트랜스파일된다
하지만 이런경우라면...?
- typescript
const enum Player {
Rudy = 'rudy',
Dvaid = 'daivd',
Jay = 'jay',
Kim = "김수한무 거북이와 두루미 삼천갑자 동방삭 치치카포 사리사리센타 워리워리 세브리깡 무두셀라 구름이 허리케인에 담벼락 담벼락에 서생원 서생원에 고양이 고양이엔 바둑이 바둑이는 돌돌이 "
}
const player: Player = Player.Rudy
javascript (transpiled)
"use strict"; const player = "\uAE40\uC218\uD55C\uBB34 \uAC70\uBD81\uC774\uC640 \uB450\uB8E8\uBBF8 \uC0BC\uCC9C\uAC11\uC790 \uB3D9\uBC29\uC0AD \uCE58\uCE58\uCE74\uD3EC \uC0AC\uB9AC\uC0AC\uB9AC\uC13C\uD0C0 \uC6CC\uB9AC\uC6CC\uB9AC \uC138\uBE0C\uB9AC\uAE61 \uBB34\uB450\uC140\uB77C \uAD6C\uB984\uC774 \uD5C8\uB9AC\uCF00\uC778\uC5D0 \uB2F4\uBCBC\uB77D \uB2F4\uBCBC\uB77D\uC5D0 \uC11C\uC0DD\uC6D0 \uC11C\uC0DD\uC6D0\uC5D0 \uACE0\uC591\uC774 \uACE0\uC591\uC774\uC5D4 \uBC14\uB451\uC774 \uBC14\uB451\uC774\uB294 \uB3CC\uB3CC\uC774 " /* Player.Kim */
트랜스파일된 코드가 너무 더러워진다
2. string literal Union
typescript
type Player = 'rudy' | 'david' | 'jay'
const player: Player = 'rudy'
javascript (transpiled)
"use strict";
const player = 'rudy';
- 마찬가지로 트랜스파일 된 코드가 더러워질 수 있다
3. 배열 이용하기
const playerArr = ['rudy', 'david', 'jay'] as const
type Player = typeof playerArr[number] // 'rudy', 'david', 'jay'
const player: Player = 'jay'
4. 객체 이용하기
const playerObj = {
rudy: 'rudy',
david: 'david',
jay: 'jay'
} as const
type Player = typeof playerObj[keyof typeof playerObj] // 'rudy' | 'david' | 'jay'
const player: Player = playerObj.rudy
제네릭으로 타입 만들어 활용하기
type Union<T extends ReadonlyArray<any> | Record<string, any>> = T[keyof T]
const playerObj = {
rudy: 'rudy',
david: 'david',
jay: 'jay'
} as const
const player: Union<typeof playerObj> = playerObj.rudy