[Typescript] Enums 열거형

eunn·2019년 12월 31일
2

열거형을 사용하면 이름이 있는 상수들을 정의할 수 있습니다.
enum키워드를 이용하여 정의할 수 있습니다.
Typescript는 숫자 및 문자열 기반 열거형을 모두 제공합니다.

숫자 열거형 (Numeric enums)

enum Direction {
  Up,
  Down,
  Left,
  Right,
}
  • 초기화 되지 않은 열거형의 첫번째 값은 '0'으로 시작합니다.
    이 때, Up = 1 이라고, 값을 지정해 주면, 다음부터는 자동증가하여 Direction.Up1, Down2, Left3, Right4 가 됩니다.

  • 초기화가 되지 않은 열거형은 상수 또는 다른 상수 열거형의 멤버로 초기화된 숫자 열거형을 따라야할 필요가 있으며, 아래와 같은 경우는 허용되지 않습니다.

enum E {
    A = getSomeValue(),
    B, // 오류 ! A 는 상수로 초기화되지 않았으므로 B에는 초기화가 필요합니다.
}

아래의 코드처럼 중간 중간에 전혀 다른 값으로 초기화 시킬 경우,
그 다음의 값은 무조건 이전 값에서 +1 이 된 값을 지니게 됩니다.
즉, Down = 2, Right = 6 이 됩니다.

enum Direction {
  Up = 1,
  Down,
  Left = 5,
  Right,
}

열거형의 이름을 사용하여 타입을 선언할 수 있습니다.

enum Response1 {
    No = 0,
    Yes = 1,
}

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

respond("Princess Caroline", Response1.Yes)

계산된 상수 멤버 (Computed and constant members)

각 열거형 멤버에는 constant 또는 computed 중 하나일 수 있는 값이 있습니다.
열거형 멤버는 상수 열거형 표현식으로 초기화됩니다.
1. 리터럴 열거 표현식 (기본적으로 문자 리터럴 또는 숫자 리터럴)
2. 이전에 정의된 상수 열거형 멤버 (다른 열거형에서 올 수 있음)에 대한 참조
3. 괄호로 묶인 상수 열거형 표현식
4. 상수 열거형 표현식에 적용된 +, -, ~ 단항 연산자 중 하나
5. +, -, *, /, %, <<, >>, >>>, &, |, ^ 바이너리 연산자에 사용된 상수 열거형 표현식
(상수 열거형 표현식이 NaN 또는 Infinity 로 평가되는 것은 컴파일 타임 에러입니다.)

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

문자 열거형 (String enums)

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}

문자 열거형은 자동 증가 동작을 하지 않지만, "직렬화(serialize)"하는 이점이 있습니다.
문자 열거형을 사용하면 열거형 멤버 자체의 이름과 독립적으로 코드가 실행될 때, 읽기 쉬운 값을 제공합니다.

별종 열거형 (Heterogeneous enums)

숫자형 + 문자형 열거형을 말하지만,
JavaScript의 런타임 동작을 실제로 사용하려고 하지 않는 한 이렇게 하지 않는 것이 좋다고 합니다.

enum BooleanLikeHeterogeneousEnum {
    No = 0,
    Yes = "YES",
}

통합 열거형 및 열거형 멤버 타입 (Union enums and enum member types)

리터럴 열거형 멤버는 초기화된 값이 없거나 다음 값으로 초기화 된 값이 있는 상수 열거형 멤버입니다.

  • 문자열 리터럴 (예: "foo", "bar", "baz")
  • 숫자 리터럴 (예: 1, 100)
  • 숫자 리터럴에 적용되는 단항 마이너스 (예: -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,
    //    ~~~~~~~~~~~~~~~~ 오류!
    radius: 100,
}

두번째, 열거 타입 자체가 각 열거형 멤버의 합집합(union) 이 된다는 것입니다.
조합 열거형을 사용하는 타입 시스템이 열거형 자체에 존재하는 정확한 값들을 알고있다는 사실을 활용할 수 있습니다.
이 때문에 TypeScript는 값을 잘못 비교하는 버그를 잡을 수 있습니다.

enum E {
    Foo,
    Bar,
}

function f(x: E) {
    if (x !== E.Foo || x !== E.Bar) {
        //             ~~~~~~~~~~~
        // 오류! 연산자 '!==' 는 'E.Foo' 및 'E.Bar' 타입에 적용할 필요가 없습니다. 이미 E 타입은 Foo 와 Bar 만 존재하기 때문에!
    }
}

런타임시 열거형 (Enums at runtime)

열거형은 런타임에 존재하는 실제 객체입니다.

enum E {
    X, Y, Z
}

실제로 함수에 전달 될 수 있습니다.

function f(obj: { X: number }) {
    return obj.X;
}

// 작동합니다. 왜냐하면 `E` 는 숫자인 `X` 라는 속성을 가지고있기 떄문입니다.
f(E);

역매핑 (Reverse mappings)

숫자 열거형 멤버는 열거형 값에서 열거형의 이름으로 역 매핑(reverse mapping) 을 받을 수 있습니다.

enum Color {
    Red
}
let red = Color.Red;
let nameOfRed = Color[red]; // "Red"

이 생성된 코드에서 열거형은 전방향(forward) (name -> value) 매핑과 역방향(reverse) (value -> name) 매핑을 모두 저장하는 객체로 컴파일됩니다.
다른 열거형 멤버에 대한 참조는 항상 속성 접근으로 방출되며 결고 인라인(inline)되지 않습니다.

문자열 열거형 멤버는 역매핑을 생성하지 않습니다.

const 열거형 (const enums)

  • const 열거형은 상수 열거형 표현식만 사용할 수 있으며 (즉, 계산된 멤버를 가질 수 없습니다.), 일반 열거형과 달리 컴파일하는 동안 완전히 제거됩니다.
  • const 열거형 멤버는 사용하는 사이트에서 인라인(inline)됩니다.
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 enums)

declare enum Enum {
    A = 1,
    B,
    C = 2
}

declare는 객체를 사용할 수 없고, 타입을 선언하는 경우에만 가능합니다.
(지금 공부한 것만으로는 declare에 대해 정확히 표현할 수 없을 것 같습니다. 좀 더 자세히 공부하고 난 후, 첨부하도록 하겠습니다.)

참고자료

[enum과 const enum 의 차이][TS 8. enum vs const enum | FELog](https://jaeyeophan.github.io/2018/06/16/TS-8-enum-vs-const-enum/)
[enum을 사용하는 이유]
https://medium.com/@seungha_kim_IT/typescript-enum%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-3b3ccd8e5552
[about declare]
https://stackoverflow.com/questions/28818849/how-do-the-different-enum-variants-work-in-typescript

profile
사람-컴퓨터와 소통하고 싶은 병아리 개발자입니다🐥

0개의 댓글