enum과 as const는 탄생한 목적 자체가 다르다.
enum은 서로 연관된 상수들을 하나의 네임스페이스로 묶어 추상화하기 위해 도입된 것이다. 이를 통해 코드만 보더라도 의도를 명확히 알 수 있어 가독성을 높일 수 있다.
반면 as const는 타입 단언의 한 종류로써 리터럴 타입의 추론 범위를 줄이고 값의 재할당을 막기 위한 목적으로 만들어졌다.
프론트엔드 입장
- enum은 번들링된 코드의 용량이 기대하는 것보다 조금 더 클 수 있다
- 프론트엔드용 JS는 브라우저의 페이지로드마다 브라우저가 JS파일을 다운받는다
- JS 파일을 다운로드 받는 시간이 짧아질수록 사용자 입장에서 최초 페이지 진입 시 로딩 시간이 줄어드는 효과를 가짐
- 그치만 node.js는 자바스크립트 소스코드를 받아서 읽어오는 시점은, node.js 서버가 배포될때말고 없음
- 한번 켜진 node.js 서버는 모든 Js코드가 해당 서버의 메모리에 올라가 있고, 다시 JS을 읽을 일이없다
트리쉐이킹 관점
- 트리쉐이킹 : 만들고 아무데에서도 쓰지 않는 변수를 찾아서 코드에서 아예 삭제해주는 기능
- enum은 크리쉐이킹이 잘안돼서 문제 → 애초에 대상이 아님 → 그리고 얼마안되는데 최적화한다해서 의미가있나? →걍 eunm 써라!
원시값의 as const
const greeting1 = "Hello, World!"; // "Hello, World!"로 추론
let greeting2 = "Hello, World!"; // string으로 추론
원시값은 let으로 할당된 애를 상위타입으로 범위가 확장된다
따라서 let으로 선언된 변수에 as const를 달아주면 const와 같은효과다.
Object 리터럴의 as const
참조 타입이기 때문에 const로 선언하더라도, 내부 프로퍼티의 추론 범위가 한정되지도 않고, 값을 변경할 수도 있습니다.
const language = {
korean: "ko", // string으로 추론
english: "en", // string으로 추론
};
language.korean = "kkk"; // kkk로 korean프로퍼티가 변경
language.english = "eee"; // eee로 english프로퍼티가 변경
as const 사용시
const language = {
korean: "ko", // "ko"로 추론, readonly 프로퍼티로 변경
english: "en", // "en"로 추론, readonly 프로퍼티로 변경
} as const;
// Error: Cannot assign to 'korean' because it is a read-only property
language.korean = "kkk";
// Error: Cannot assign to 'english' because it is a read-only property.
language.english = "eee";
그리고 as const 사용하면 중첩요소들까지 readonly로 된다
const obj = {
a: 10,
b: [20, 30],
c: {
d: {
e: {
greeting: "Hello",
},
},
},
} as const;
// 다음과 같이 추론됨.
const obj: {
readonly a: 10;
readonly b: readonly [20, 30];
readonly c: {
readonly d: {
readonly e: {
readonly greeting: "Hello";
};
};
};
};
enum 리버스 매핑
- 상수들을 하나로 묶어 추상화시킬 목적 → enum
// transpile 이전
enum COLOR {
red,
blue,
green
}
// transpile 이후
var COLOR;
(function (COLOR) {
COLOR[COLOR["red"] = 0] = "red";
COLOR[COLOR["blue"] = 1] = "blue";
COLOR[COLOR["green"] = 2] = "green";
})(COLOR || (COLOR = {}));
var COLOR = {
red: 0,
blue: 1,
green: 2,
'0': 'red',
'1': 'blue',
'2': 'green'
}
// 이런 형태로 객체가 변환되는 거임 -> 각 프로퍼티에 특정 값들이 매핑됨 + 반대로도 됨 (**리버스 매핑**)
- 트랜스파일 이후 다음과 같은 객체가 생김
const enum
// transpile 이전
const enum COLOR {
red,
blue,
green,
}
console.log(COLOR.red);
console.log(COLOR.blue);
console.log(COLOR.green);
// transplie 이후
console.log(0 /* red */);
console.log(1 /* blue */);
console.log(2 /* green */);
- 얘는 타입스크립트 트랜스파일 이후 파일을 보면 객체 실체를 안만든다.
트랜스파일링 필요한 경우
→이때 enum을 사용하자
enum LogLevel {
ERROR,
WARN,
INFO,
DEBUG,
}
function logImportant(level: LogLevel, message: string): void {
if (level > LogLevel.WARN) return;
const logLevel = LogLevel[level];
console.log(`[${logLevel}] ${message}`);
}
// logImportant(0, "This is a error level message.");
logImportant(LogLevel.ERROR, "This is a error level message.");
// logImportant(1, "This is a warn level message.");
logImportant(LogLevel.WARN, "This is a warn level message.");
// logImportant(2, "This is a info level message.");
logImportant(LogLevel.INFO, "This is a info level message.");
// logImportant(3, "This is a debug level message.");
logImportant(LogLevel.DEBUG, "This is a debug level message.");
// 출력
// [ERROR] This is a error level message.
// [WARN] This is a warn level message.
→ 위에 코드처럼 에러처리의 우선순위를 나타낼때 사용하는 것이 좋다
https://inpa.tistory.com/entry/TS-📘-타입스크립트-enum-정리