tsc는
enum Zoo { Cat, Tiger }
위의 코드를
var Zoo; (function (Zoo){ Zoo[Zoo["Cat"] = 0] = "Cat"; Zoo[Zoo["Tiger"] = 1] = "Tiger"; )(Zoo || (Zoo{}))
로 변경한다.
lookup object를 참조한다고 할 수 있다. 이것의 목적은 두 가지입니다 : 문자열에서 숫자로의 매핑 역할을하는 것. Zoo.Cat 또는 Zoo[ 'Cat']를 쓸 때, 숫자에서 문자열로의 매핑 역할을 합니다. 역 매핑은 디버깅 또는 로깅 목적에 유용합니다. 종종 0 또는 1 값을 가지며 해당 문자열 “Cat”또는 “Tiger”를 가져옮니다.
TypeScript에서는 컴파일러가 알아야 할 사항을 “선언”할 수 있지만 실제로 코드를 생성 되지는 않습니다. 이는 유형 정보가 필요하지만 컴파일러에서 생성된 코드가 필요없는 일부 객체 (예 : $)를 정의하는 jQuery와 같은 라이브러리가있는 경우에 유용합니다. 명세와 다른 문서는 이런 식으로 된 선언을 “앰비언트 (Ambient)“문맥에 있는 것으로 언급한다; .dts 파일의 모든 선언은 “앰비언트”(명시적 선언 수정자를 필요로하거나 선언 유형에 따라 암시적으로 지정하는 것)이 중요합니다.
성능 및 코드 크기 때문에 컴파일 할 때 열거 형 멤버에 대한 참조를 숫자로 대체하는 것이 바람직합니다.
enum Foo { X = 4 } var y = Foo.X; // emits "var y = 4";
spec은 이 대체를 호출합니다. 개인적으로 소리가 좋기때문에 “inlining”으로 명명하겠다. 때때로 열거형 값이 향후 API 버전에서 변경 될 수 있기 때문에 열거형 멤버가 인라인되지 않게하려는 경우가 있습니다.
열거 형의 각 측면별로 이것을 분해 해 봅시다. 불행히도이 네 섹션은 다른 모든 섹션의 용어를 참조 할 것 이므로 이 모든 것을 두 번 이상 읽어야합니다.
Enum 멤버는 계산됨 이거나 아니거나다. 스펙은 비계산 멤버는 constant라 명명한다, 그러나 const와 충돌을 회피하기 위해서 non-computed라 부르겠다.
computed enum 멤버는 컴파일 타임에 값을 알 수 없는 멤버입니다. 물론 계산 된 멤버에 대한 참조는 인라인 될 수 없습니다. 반대로 계산되지 않은 열거 형 멤버는 한 번 컴파일 타임에 알려진 값입니다. 계산되지 않은 멤버에 대한 참조는 항상 인라인됩니다.
어떤 enum 멤버가 계산되고 계산되지 않는 것입니까? 첫째, const enum의 모든 멤버는 이름에서 알 수 있듯이 상수 (즉, 계산되지 않음)입니다. 비 const 열거 형의 경우에는 앰비언트(선언) enum인지 또는 non-ambient enum인지 여부에 따라 다릅니다.
declare enum (즉, ambient enum)의 멤버는 초기화가 있는 경우에만 상수입니다. 그렇지 않으면 computed이다. declare enum에서 numeric 초기화만 사용할 수 있습니다. 예:
declare enum Foo { X, // computed Y = 2, // Non-computed Z, // Computed! Not 3! Careful! Q = 1 + 1 // Error }
마지막으로 non-declare non-const enum의 멤버는 항상 계산 된 것으로 간주됩니다. 그러나 컴파일 타임에 계산할 수 있는 경우 해당 초기화식이 상수로 축소됩니다. 이것은 비 const 열거 형 멤버가 결코 인라인되지 않음을 의미합니다 (이 동작은 TypeScript 1.5에서 변경되었으므로 맨 아래의 “TypeScript에서 변경된 사항”참조)
enum선언은 const수정자를 가질 수 있다. 만약 enum이 const라면 모든 멤버는 inline으로 처리된다.
const enum Foo { A = 4 } var x = Foo.A; // emitted as "var x = 4;", always
const enum은 컴파일 할 때 lookup object를 생성하지 않습니다. 이러한 이유 때문에 위 참조 코드에서 Foo를 참조하는 것은 회원 참조의 일부분을 제외하고는 오류입니다. 런타임에는 Foo 객체가 없습니다.
enum 선언에 const 한정자가없는 경우 멤버가 계산되지 않은 경우에만 멤버에 대한 참조가 인라인됩니다. non-const, non-declare enum은 lookup object를 생성합니다.
중요한 서문은 TypeScript의 declare이 매우 구체적인 의미를 갖는다는 것입니다.이 객체는 다른 곳에 존재합니다. 기존 개체를 설명하기위한 것입니다. 실제로 존재하지 않는 객체를 정의하기 위해 declare를 사용하면 나쁜 결과가 발생할 수 있습니다. 우리는 나중에 그것들을 탐구 할 것입니다.
declare enum은 lookup object를 생성하지 않습니다. 해당 멤버에 대한 참조는 해당 멤버가 계산되면 inline됩니다 (위의 computed vs non-computed 항목 참조).
declare enum에 대한 다른 형식의 참조가 허용된다는 점에 유의해야합니다. 이 코드는 컴파일 오류가 아니지만 런타임에 실패합니다.
// Note: Assume no other file has actually created a Foo var at runtime declare enum Foo { Bar } var s = 'Bar' var b = Foo[s]; // Fails
이 오류는 “컴파일러에게 거짓말하지 마십시오”라는 범주에 속합니다. 런타임에 Foo라는 객체가 없으면 declare enum Foo!를 작성하지 마십시오!
declare const enum은 –preserveConstEnums (아래 참조)를 제외하고 const enum과 다르지 않습니다.
non-declare enum은 const가 아닌 경우 lookup object를 생성합니다. inlining은 위에 설명되어 있습니다.
이 플래그는 정확히 한 가지 효과를 냅니다. non-declare const enum은 조회 객체를 방출합니다. 인라인은 영향을받지 않습니다. 이것은 디버깅에 유용합니다.
가장 일반적인 실수는 일반 enum이나 const enum이 더 적절한 경우 선언 열거 형을 사용하는 것입니다. 일반적인 형식은 다음과 같습니다.
module MyModule { // Claiming this enum exists with 'declare', but it doesn't... export declare enum Lies { Foo = 0, Bar = 1 } var x = Lies.Foo; // Depend on inlining } module SomeOtherCode { // x ends up as 'undefined' at runtime import x = MyModule.Lies; // Try to use lookup object, which ought to exist // runtime error, canot read property 0 of undefined console.log(x[x.Foo]); }
기억하십시오 : 실제로 존재하지 않는 것을 declare하지 마십시오. 항상 inlining을 원하면 const enum을 사용하고, lookup object를 원한다면 enum을 사용하십시오.
TypeScript 1.4와 1.5 사이에는 non-declare non-const enums의 모든 멤버를 computed로 처리하도록 변경되었습니다 (https://github.com/Microsoft/TypeScript/issues/2183 참조). 그들은 리터럴로 명시적으로 초기화됩니다. 이렇게 말하면, 인라인 동작을 보다 예측 가능하고보다 명확하게 const enum의 개념을 일반 enum으로부터 분리하는 “아기 분리 해제”. 이 변경 이전에 non-const enum의 non-computed 멤버는 보다 적극적으로 inline되었습니다.
enum을 사용하면 이름이 부여된 상수 집합을 정의할 수 있다.
enum Direction { Up=1, Down, Left, Right } // Direction.Up은 값 1, Down은 2, Left는 3, Rright는 4를 가진다. // 1로 초기화되고, 모든 후속멤버는 자동증가한다.
enum E { A = getSomeValue(), B, // error! 'A' is not constant-initialized, so 'B' needs an initializer }
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT", }
이론적으로는 가능하지만 어떤 필요성이 있는지는 의문
enum BooleanLikeHeterogenousEnum { No = 0, Yes = "YES", }
각 enum 멤버는 상수 또는 계산됨 중 하나의 값을 가진다.
멤버가 상수로 간주되는 경우
constant enum expression은 compile time에 모두 계산 가능한 TypeScript 수식의 부분집합이다.
constant enum expression이 NaN 또는 Infinity로 평가되는 것은 컴파일 타임 오류입니다.
다른 경우의 모든 enum 멤버는 computed로 간주됩니다.
enum FileAccess { // constant members None, Read = 1 << 1, Write = 1 << 2, ReadWrite = Read | Write, // computed member G = "123".length }
Enums는 런타임에 존재하는 실제 객체이다.
enum E { X, Y, Z } function f(obj: { X: number }) { return obj.X; } // Works, since 'E' has a property named 'X' which is a number. f(E); // enum은 함수에 매개변수로 전달될 수 있다.
Enums은 런타임에 존재하는 실제 객체이지만 keyof 키워드는 일반적인 객체에서 기대하는 것과 다르게 작동합니다. 대신 keyof typeof를 사용하여 모든 Enum 키를 문자열로 나타내는 Type을 가져옵니다.
enum LogLevel { ERROR, WARN, INFO, DEBUG } /** * This is equivalent to: * 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');
numeric enums 멤버는 구성원에 대한 속성 이름이있는 개체를 만드는 것 외에도 enum 값에서 enum 이름으로 역매핑을 가져옵니다.
enum Enum { A } let a = Enum.A; let nameOfA = Enum[a]; // "A"
string enums 멤버는 역 매핑을 전혀 생성하지 않는다는 것을 명심하라
대부분의 경우 열거 형은 완벽하게 유효한 솔루션입니다. 그러나 때로는 요구 사항이 더 엄격합니다. enum 값에 액세스 할 때 여분의 생성 된 코드 및 추가 indirection의 비용을 지불하지 않으려면 const 열거 형을 사용할 수 있습니다. Const enum은 enum의 const 수정자를 사용하여 정의됩니다.
const enum Enum { A = 1, B = A * 2 }
Const enum은 상수 enum 표현식 만 사용할 수 있으며 일반 enum과 달리 컴파일하는 동안 완전히 제거됩니다. Const enum 멤버는 사용되는 곳에 인라인됩니다. const 열거 형은 computed 멤버를 가질 수 없기 때문에 가능합니다.
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right] // 이것은 다음과 같은 코드로 생성된다. var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking
앰비언트 열거 형은 이미 존재하는 열거 형의 모양을 설명하는 데 사용됩니다.
declare enum Enum { A = 1, B, C = 2 }
ambient 과 non-ambient enums의 중요한 차이점 중 하나는 일반 enum에서는 초기화가 없는 멤버는 이전 enum 멤버가 constant로 간주되는 경우 constant로 간주된다는 것입니다. 대조적으로, 초기화가 없는 ambient(및 non-const) enum 멤버는 항상 **computed”로 간주됩니다.