Typescript에는 enum 타입이 있습니다.
enum 타입은 열거형 타입으로 의미가 명확한 코드와 코드의 가독성을 제공하기 위해 존재합니다.
enum에는 숫자형 타입과 문자형 타입이 존재합니다.
숫자형 타입
enum DirectionNumber {
UP,
DONW,
RIGHT,
LEFT,
}
enum DirectionNumberWithNumber {
UP = 0,
DONW = 1,
RIGHT = 2,
LEFT = 3,
}
숫자형 타입에서는 value의 할당을 생략할 수 도 있습니다.
할당을 생략하게 되면 값은 0 부터 차례대로 할당됩니다.
(ex. UP = 0, DOWN = 1, RIGHT = 2, LEFT = 3)
문자형 타입
enum DirectionString {
UP = "up",
DONW = "down",
RIGHT = "right",
LEFT = "left",
}
문자형 타입에서는 값의 할당을 해주어야 합니다.
만약에 빼먹으면 숫자형 타입으로 인식이 됩니다.
빼먹었을때 경우에 따라 error를 발생하는데 아래에서 살펴보겠습니다.
잠깐 딴길로 새면
enum에서는 키 값들이 상수로 취급됩니다.
따라서 값은 enum내에서는 같은 키값을 사용할 수가 없습니다.
enum test {
a: string,
a: string, // error
}
또한 enum은 선언적 할당을 이용해 확장할 수 있습니다.
enum DirectionNumber {
UP,
DONW,
RIGHT,
LEFT,
}
enum DirectionNumber {
CENTER = 5,
}
console.log(DirectionNumber)
/*
{
'0': 'UP',
'1': 'DONW',
'2': 'RIGHT',
'3': 'LEFT',
'5': 'CENTER',
UP: 0,
DONW: 1,
RIGHT: 2,
LEFT: 3,
CENTER: 5
}
*/
하지만 선언이후에 값을 변경할수는 없습니다.
아래와 같이 기존의 키 값에 존재하지 않는 키값을 추가해줄순 있지만
원래 enum의 역할은 할수가 없습니다.
모호한 타입
enum DirectionString {
MIDDLE = 0,
UP = "up",
DONW = "down",
RIGHT = "right",
CENTER = 1,
LEFT = "left",
}
숫자형과 문자형을 섞으면 위와 같은 복잡한 enum이 생성되게 됩니다.
공식문서에서는 위의 타입을 추천하지 않고 있습니다.
만약 위의 모호한 타입에서 숫자형 타입의 값을 할당하지 않으면 어떻게 될까요??
enum DirectionString {
MIDDLE, // 0으로 할당
UP = "up",
DONW = "down",
RIGHT = "right",
CENTER, // error
LEFT = "left",
CENTER, // error
}
비할당된 타입이 첫번째 위치에 올때는 0부터 인식이 됩니다.
하지만 중간이나 마지막에 위치하게 되면 원하는대로 동작하지 않습니다.
숫자형 타입과 문자형타입의 차이는 타입의 종류 뿐만 아니라 transpile(ts -> js) 후에도 나타납니다.
숫자형, 문자형 타입을 두개를 선언하고 결과값을 살펴보겠습니다.
enum DirectionNumber {
UP,
DONW,
RIGHT,
LEFT,
}
enum DirectionString {
UP = "up",
DONW = "down",
RIGHT = "right",
LEFT = "left",
}
console.log(DirectionNumber);
/*
{
'0': 'UP',
'1': 'DONW',
'2': 'RIGHT',
'3': 'LEFT',
UP: 0,
DONW: 1,
RIGHT: 2,
LEFT: 3
}
*/
console.log(DirectionString);
// { UP: 'up', DONW: 'down', RIGHT: 'right', LEFT: 'left' }
숫자형 타입에는 값으로도 접근을 할수 있게끔 mapping이 되고 있는것을 확인할 수 있습니다.
console.log(DirectionNumber["0"]);
console.log(DirectionString["up"])
// UP
// undefined
이렇게 숫자형 타입에서 값으로도 접근할 수 있게 해주는 것을 reverse mapping이라고 합니다.
reverse mapping이 생성되는 이유는 transpile된 코드를 살펴보면 확인할 수 있습니다.
// reverse mapping 중
// DirectionNumber["UP"] = 0은 0을 반환함
var DirectionNumber;
(function (DirectionNumber) {
DirectionNumber[DirectionNumber["UP"] = 0] = "UP";
DirectionNumber[DirectionNumber["DONW"] = 1] = "DONW";
DirectionNumber[DirectionNumber["RIGHT"] = 2] = "RIGHT";
DirectionNumber[DirectionNumber["LEFT"] = 3] = "LEFT";
})(DirectionNumber || (DirectionNumber = {}));
var DirectionString;
(function (DirectionString) {
DirectionString["UP"] = "up";
DirectionString["DONW"] = "down";
DirectionString["RIGHT"] = "right";
DirectionString["LEFT"] = "left";
})(DirectionString || (DirectionString = {}));
잠깐 딴길로 새서 typescript에서 let과 const의 차이를 알아보겠습니다.
원시값의 타입과 참조값의 타입의 경우를 살펴보겠습니다.
원시 타입
let 변수의 경우 value의 타입이 나타나는 것을 볼 수 있습니다.
여기에 as const를 붙이면 어떻게 될까요?
타입이 "say hello"로 const에서의 경우와 같게끔 나오는 것을 확인할 수 있습니다.
원래 let 변수에는 재할당이 가능합니다.
하지만 as const를 사용함으로써 재할당이 불가능하게 되었습니다.
참조 타입
객체를 const로 선언한 후에 타입을 살펴 보겠습니다.
const로 선언하였지만 value의 타입들이 mapping된 것을 확인할 수 있습니다.
이렇게 되면 추후에 값을 변경할 수가 있게 됩니다.
const로 선언한 객체에도 값을 변환할 수 없게 할 수 있습니다.
as const를 붙여주어 readonly가 추가된 것을 확인할 수 있습니다.
이렇게 되면 test 변수의 값을 변경할 수가 없게 됩니다.
이 as const를 이용하여 enum을 대신할 수 있습니다.
const enum, enum, as const
자 이제 거의 다왔습니다.
enum DirectionNumber {
UP,
DONW,
RIGHT,
LEFT,
}
const DirectionObject = {
UP: 0,
DOWN: 1,
RIGHT: 2,
LEFT: 3
} as const
console.log(DirectionNumber.UP); // 0
console.log(DirectionObject["UP"]); // 0
위의 경우 두개의 출력값은 같고 DirectionObject는 readonly 속성을 가지게 됩니다.
이제 object를 enum 대신 사용할수 있을것만 같습니다.
아래와 같이 속성을 추가할 수도 있습니다.
const DirectionObject = {
UP: 0,
DOWN: 1,
RIGHT: 2,
LEFT: 3
}
DirectionObject["CENTER"] = 4
Object.defineProperty(DirectionObject, "CENTER", { value: 4, writable: false, enumerable: true})
DirectionObject["CENTER"] = 5
예제 코드에서는 writable: false를 사용하여 값의 재할당이 불가능하게 하였습니다.
위의 예제에 as const를 사용하면 더 역할을 잘 수행할 수 있을것 같습니다.
하지만 객체가 enum의 역할을 수행하는 것은 코드를 접했을때 enum 보다는 확실한 메시지를 전달할 수 없습니다.
나는 열거형 타입이야 라고 외치고 있는 enum을 사용하는 것이 코드의 의미를 파악하기 더 쉽지 않을까요??!!
하지만 enum은 객체에 비해 transpile되는 코드량이 많고 reverse mapping의 경우 불필요한 코드의 생산을 초래할 수 있습니다.
숫자형 열거 타입에서 값으로 접근하는 경우는 특수한 경우와 용도가 아니라면 사용되지 않을것 같습니다.(Log에 error 찍는 경우???)
근데 왜 불필요한 코드가 적어야 할까요??
사용자의 디바이스에서 transpile된 코드를 실행하게 됩니다.
불필요한 코드가 줄어들면 파일의 크기가 줄어들고 실행이 간결해 집니다.
사용자는 로드를 더 빠르게 할 수 있고 화면에 렌더링이 더 빠르게 할 수 있다라는 뜻이 됩니다.
이런 문제를 해결할 수 있는 것이 enum앞에 const를 붙이는 것입니다.
위의 이미지는 enum을 const로 선언한 것과 하지 않은것의 transpile된 결과 입니다.
const enum을 transpile하는 코드는 존재하지 않고 값만 출력하고 있는 것을 볼 수 있습니다.
자 이제 어떤걸 사용해야 하는지 알수 있을것 같습니다.
enum을 사용하여 좀 더 의미있는 코드를 작성합니다.
근데 이때 const를 곁들이면 transpile 된 코드의 양을 줄일수 있습니다!!
Object와 enum의 차이
- object 는 코드내에서 새로운 속성을 자유롭게 추가할 수 있지만, enum 은 선언할때 이후에 변경할 수 없습니다.
- object 의 속성값은 JS가 허용하는 모든 타입이 올 수 있지만, enum 의 속성값으로는 문자열 혹은 숫자만 허용됩니다.
출처:
https://www.typescriptlang.org/docs/handbook/enums.html#computed-and-constant-members
Handbook - Enums
How TypeScript enums work
www.typescriptlang.org
https://sambalim.tistory.com/142
Typescript Enum이란?
Javascript와 다르게 Typescript에서는 Enum을 제공합니다. Enum이 무엇인지, Enum을 사용하면 어떤 이점이 있는지 알아봅시다. Enum? enum 은 enumerated type(열거형)을 의미합니다. Enum은 값들의 집합을 명명..
sambalim.tistory.com
https://velog.io/@logqwerty/Enum-vs-as-const
Enum vs as const
Typescript에서 가독성을 높이기 위한 일환으로 서로 연관된 상수들을 하나의 namespace에 묶어 관리할 때, 다음과 같이 enum키워드를 사용해 Enum type을 선언하거나객체 리터럴에 as const라는 type assertion
velog.io
'Frontend > Typescript' 카테고리의 다른 글
Typescript class 🏛 (0) | 2022.04.19 |
---|---|
Typescript 사용 이유 (0) | 2022.03.23 |
Typescript type vs interface (0) | 2022.03.23 |
Typescript 유틸리티 타입 [Utility Types] (0) | 2022.03.02 |
Typescript '<variable>' is declared but its value is never read. (0) | 2022.03.02 |