공부공부/TS

[typescript 핸드북] 06. 열거형

고생쨩 2024. 2. 19. 09:32
728x90

typescript 핸드북 학습내용 정리
https://typescript-kr.github.io/pages/the-handbook.html

열거형

숫자 열거형

enum Direction {
    Up = 1,
    Down,
    Left,
    Right,
}
// 첫번째값만 지정하면 뒤는 자동으로 증가된 값을 갖는다.
// Down = 2, Left = 3, Right = 4
enum Direction {
    Up,
    Down,
    Left,
    Right,
}
// 지정하지 않는 경우 0부터 시작한다.
// Up = 0, Down = 1 ...
enum Response {
    No = 0,
    Yes = 1,
}

function respond(recipient: string, message: Response): void {
    // ...
}

respond("Princess Caroline", Response.Yes)
// 요렇게 사용

숫자 열거형은 계산된 멤버와 상수 멤버를 섞어서 사용할 수 있음.
다만, 숫자 상수 혹은 초기화되지 않은 열거형 이후에 나와야함.

문자열 열거형

문자열 열거형에서 각 멤버들은 문자열 리터럴 또는 다른 문자열 열거형의 멤버로 상수 초기화 해야함

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}
  • 숫자형처럼 자동 증가 기능은 없음
  • 직렬화가 잘됨. (값을 읽었을때 의미가 명확)

이종 열거형

숫자와 문자를 섞어서 사용할 수 있지만 그렇게할 이유는 없음

계산된 멤버와 상수 멤버

상수 열거형 표현식

  1. 리터럴 열거형 표현식 (기본적으로 문자 리터럴 또는 숫자 리터럴)
  2. 이전에 정의된 다른 상수 열거형 멤버에 대한 참조 (다른 열거형에서 시작될 수 있음)
  3. 괄호로 묶인 상수 열거형 표현식
  4. 상수 열거형 표현식에 단항 연산자 +, -, ~ 를 사용한 경우
  5. 상수 열거형 표현식을 이중 연산자 +, -, *, /, %, <<, >>, >>>, &, |, ^ 의 피연산자로 사용할 경우
  6. 상수 열거형 표현식 값이 NaN 이거나 Infinity 이면 컴파일 시점에 오류가 납니다.

위에 포함되지 않는 경우는 계산된 것으로 간주

enum FileAccess {
    // 상수 멤버
    None,
    Read    = 1 << 1,
    Write   = 1 << 2,
    ReadWrite  = Read | Write,
    // 계산된 멤버
    G = "123".length
}

유니언 열거형과 열거형 멤버 타입

리터럴 열거형 멤버는 초기화 값이 존재하지 않거나, 아래 값들로 초기화되는 멤버

  • 문자 리터럴 (예시. “foo”, "bar, “baz”)
  • 숫자 리터럴 (예시. 1, 100)
  • 숫자 리터럴에 단항 연산자 - 가 적용된 경우 (e.g. -1, -100)
// 열거형 멤버를 타입처럼 사용하기
enum ShapeKind {
    Circle,
    Square,
}

interface Circle {
    kind: ShapeKind.Circle;
    radius: number;
}

interface Square {
    kind: ShapeKind.Square;
    sideLength: number;
}

let c: Circle = {
    kind: ShapeKind.Square, // 오류! 'ShapeKind.Circle' 타입에 'ShapeKind.Square' 타입을 할당할 수 없습니다.
    radius: 100,
}

열거형 타입 자체가 효율적으로 각각의 열거형 멤버의 유니언이 된다.

enum E {
    Foo,
    Bar,
}

function f(x: E) {
    if (x !== E.Foo || x !== E.Bar) {
        //             ~~~~~~~~~~~
        // 에러! E 타입은 Foo, Bar 둘 중 하나이기 때문에 이 조건은 항상 true를 반환합니다.
    }
}

런타임에서 열거형

enum E {
    x,y,z
}
let a = E.x;
console.log(a);

JS로 변환 시 아래처럼 변환됨

var E;
(function (E) {
    E[E["x"] = 0] = "x";
    E[E["y"] = 1] = "y";
    E[E["z"] = 2] = "z";
})(E || (E = {}));
var a = E.x;
console.log(a);

컴파일 시점에서 열거형

enum LogLevel {
    ERROR, WARN, INFO, DEBUG
}

/**
 * 이것은 아래와 동일합니다. :
 * type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
 */
type LogLevelStrings = keyof typeof LogLevel;

function printImportant(key: LogLevelStrings, message: string) {
    const num = LogLevel[key];
    if (num <= LogLevel.WARN) {
       console.log('Log level key is: ', key);
       console.log('Log level value is: ', num);
       console.log('Log level message is: ', message);
    }
}
printImportant('ERROR', 'This is a message');

역 매핑

열거형의 값에서 이름으로 역매핑이 됨

enum Enum {
    A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"

컴파일된 js

var Enum;
(function (Enum) {
    Enum[Enum["A"] = 0] = "A";
})(Enum || (Enum = {}));
var a = Enum.A;
var nameOfA = Enum[a]; // "A"

열거형은 정방향 (name -> value) 매핑과 역방향 (value -> name) 매핑 두 정보를 모두 저장하는 객체로 컴파일됨.

const 열거형

  • 컴파일 시 완전히 제거됨
  • 계산된 멤버가 없기 때문
const enum Directions {
    Up,
    Down,
    Left,
    Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]

아래처럼 컴파일됨

var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

Ambient 열거형

이미 존재하는 열거형 타입의 모습을 묘사하기 위해 사용됨

declare enum Enum {
    A = 1,
    B,
    C = 2
}
  • 일반적인 열거형에서 초기화되지 않은 멤버가 상수로 간주하는 멤버 뒤에 있다면, 이 멤버도 상수로 간주함.
  • (const가 아닌) ambient 열거형에서 초기화되지 않은 멤버는 항상 계산된 멤버로 간주함.

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.