열거 형 유형을 프로그래밍 방식으로 열거하는 방법은 무엇입니까?


90

내가 타이프을 말해봐 enum, MyEnum등 다음과 같습니다 :

enum MyEnum {
    First,
    Second,
    Third
}

TypeScript 0.9.5에서 enum값 배열을 생성하는 가장 좋은 방법은 무엇입니까 ? 예:

var choices: MyEnum[]; // or Array<MyEnum>
choices = MyEnum.GetValues(); // plans for this?
choices = EnumEx.GetValues(MyEnum); // or, how to roll my own?

답변:


192

다음은 해당 열거 형의 JavaScript 출력입니다.

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["First"] = 0] = "First";
    MyEnum[MyEnum["Second"] = 1] = "Second";
    MyEnum[MyEnum["Third"] = 2] = "Third";
})(MyEnum || (MyEnum = {}));

다음과 같은 객체입니다.

{
    "0": "First",
    "1": "Second",
    "2": "Third",
    "First": 0,
    "Second": 1,
    "Third": 2
}

문자열 값이있는 열거 형 멤버

TypeScript 2.4는 열거 형이 문자열 열거 형 멤버 값을 가질 수있는 기능을 추가했습니다. 따라서 다음과 같은 열거 형으로 끝날 수 있습니다.

enum MyEnum {
    First = "First",
    Second = 2,
    Other = "Second"
}

// compiles to
var MyEnum;
(function (MyEnum) {
    MyEnum["First"] = "First";
    MyEnum[MyEnum["Second"] = 2] = "Second";
    MyEnum["Other"] = "Second";
})(MyEnum || (MyEnum = {}));

회원 이름 얻기

바로 위의 예를보고 열거 형 멤버를 얻는 방법을 알아낼 수 있습니다.

{
    "2": "Second",
    "First": "First",
    "Second": 2,
    "Other": "Second"
}

내가 생각 해낸 것은 다음과 같습니다.

const e = MyEnum as any;
const names = Object.keys(e).filter(k => 
    typeof e[k] === "number"
    || e[k] === k
    || e[e[k]]?.toString() !== k
);

멤버 값

일단 이름이 있으면 다음을 수행하여 해당 값을 얻기 위해 반복 할 수 있습니다.

const values = names.map(k => MyEnum[k]);

확장 클래스

이를 수행하는 가장 좋은 방법은 자신의 함수 (예 :)를 만드는 것 EnumEx.getNames(MyEnum)입니다. 열거 형에 함수를 추가 할 수 없습니다.

class EnumEx {
    private constructor() {
    }

    static getNamesAndValues(e: any) {
        return EnumEx.getNames(e).map(n => ({ name: n, value: e[n] as string | number }));
    }

    static getNames(e: any) {
        return Object.keys(e).filter(k => 
            typeof e[k] === "number"
            || e[k] === k
            || e[e[k]]?.toString() !== k
        );
    }

    static getValues(e: any) {
        return EnumEx.getNames(e).map(n => e[n] as string | number);
    }
}

흥미롭게도 (많은 사람들 이이 답변을 찬성했기 때문에) TS Playground에서 작동하도록 할 수 없습니다 .shorturl.me / jJ8G2t 내가 잘못하고있는 것이 있습니까?
Peter

1
@Peter 문자열 열거 형에 대한 정보를 포함하도록 답변을 업데이트했습니다. 또한 for of대신 문 을 사용하고 싶을 것입니다for in
David Sherret

24

타이프 라이터> = 2.4 당신이 문자열 열거 형을 정의 할 수 있습니다 :

enum Color {
  RED = 'Red',
  ORANGE = 'Orange',
  YELLOW = 'Yellow',
  GREEN = 'Green',
  BLUE = 'Blue',
  INDIGO = 'Indigo',
  VIOLET = 'Violet'
}

JavaScript ES5 출력 :

var Color;
(function (Color) {
    Color["RED"] = "Red";
    Color["ORANGE"] = "Orange";
    Color["YELLOW"] = "Yellow";
    Color["GREEN"] = "Green";
    Color["BLUE"] = "Blue";
    Color["INDIGO"] = "Indigo";
    Color["VIOLET"] = "Violet";
})(Color || (Color = {}));

다음과 같은 객체입니다.

const Color = {
  "RED": "Red",
  "ORANGE": "Orange",
  "YELLOW": "Yellow",
  "GREEN": "Green",
  "BLUE": "Blue",
  "INDIGO": "Indigo",
  "VIOLET": "Violet"
}

따라서, 문자열 열거, 필터 가지 필요의 경우 Object.keys(Color)Object.values(Color)(*) 충분합니다 :

const colorKeys = Object.keys(Color) as (keyof typeof Color)[];
console.log('colorKeys =', colorKeys);
// ["RED", "ORANGE", "YELLOW", "GREEN", "BLUE", "INDIGO", "VIOLET"]

const colorValues = Object.values(Color);
console.log('colorValues =', colorValues);
// ["Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"]

colorKeys.map(colorKey => {
  console.log(`color key = ${colorKey}, value = ${Color[colorKey]}`);
});
/*
color key = RED, value = Red
color key = ORANGE, value = Orange
color key = YELLOW, value = Yellow
color key = GREEN, value = Green
color key = BLUE, value = Blue
color key = INDIGO, value = Indigo
color key = VIOLET, value = Violet
*/

TypeScript 플레이 그라운드에서 온라인 예제 보기

(*) 이전 브라우저에 필요한 Polyfill은 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values#Browser_compatibility를 참조 하십시오.


오류가 있습니다Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Color'. No index signature with a parameter of type 'string' was found on type 'typeof Color'.
Jonas

1
@Jonas 내가 캐스트와 함께 수정했습니다 :Object.keys(Color) as (keyof typeof Color)[]
tanguy_k

감사합니다!
Jonas

9

열거 형의 이름과 인덱스를 가져 오는 함수를 추가 할 수 있습니다.

enum MyEnum {
  First,
  Second,
  Third
}

namespace MyEnum {
  function isIndex(key):boolean {
    const n = ~~Number(key);
    return String(n) === key && n >= 0;
  }

  const _names:string[] = Object
      .keys(MyEnum)
      .filter(key => !isIndex(key));

  const _indices:number[] = Object
      .keys(MyEnum)
      .filter(key => isIndex(key))
      .map(index => Number(index));

  export function names():string[] {
    return _names;
  }

  export function indices():number[] {
    return _indices;
  }
}

console.log("MyEnum names:", MyEnum.names());
// Prints: MyEnum names: ["First", "Second", "Third"]

console.log("MyEnum indices:", MyEnum.indices());
// Prints: MyEnum indices: [0, 1, 2]

당신이주의 할 수 단지 수출 _names_indices내 보낸 함수를 통해 노출보다는 consts,하지만 내 보낸 회원 열거의 멤버 있기 때문에 그들이 실제 열거 회원과 혼동되지 않도록 함수로 그것들을 가지고 틀림없이 명확하다.

TypeScript가 모든 열거 형에 대해 이와 같은 것을 자동으로 생성하면 좋을 것입니다.


7

TypeScript (생각 : 리플렉션)에는 RTTI (런타임 유형 정보)의 개념이 없으므로이를 수행하려면 트랜스 파일 된 JavaScript에 대한 지식이 필요합니다. 따라서 TypeScript 0.95를 가정합니다.

enum MyEnum {
    First, Second, Third
}

된다 :

var MyEnum;
(function(MyEnum) {
    MyEnum[MyEnum["First"] = 0] = "First";
    MyEnum[MyEnum["Second"] = 1] = "Second";
    MyEnum[MyEnum["Third"] = 2] = "Third";
}

그래서,이 자바 스크립트에서 정규 객체로 모델링 MyEnum.0 == "First"하고 MyEnum.First == 0. 따라서 모든 열거 형 이름을 열거하려면 개체에 속하고 숫자가 아닌 모든 속성을 가져와야합니다.

for (var prop in MyEnum) {         
    if (MyEnum.hasOwnProperty(prop) &&
        (isNaN(parseInt(prop)))) {
        console.log("name: " + prop);
    }
}

좋아, 이제 나는 그것을하는 방법을 당신에게 말했고, 이것은 나쁜 생각이라고 말할 수 있습니다 . 관리되는 언어를 작성하는 것이 아니므로 이러한 습관을 가져올 수 없습니다. 여전히 평범한 오래된 JavaScript입니다. 어떤 종류의 선택 목록을 채우기 위해 JavaScript의 구조를 사용하려면 평범한 오래된 배열을 사용합니다. 열거 형은 여기서 올바른 선택이 아닙니다. TypeScript의 목표는 관용적이고 예쁜 JavaScript를 생성하는 것입니다. 이런 방식으로 열거 형을 사용하면이 목표가 유지되지 않습니다.


5

David Sherret이 제안한 솔루션을 사용하고 사용할 수있는 npm 라이브러리를 작성했습니다 enum-values.

힘내 : 열거 형 값

// Suppose we have an enum
enum SomeEnum {
  VALUE1,
  VALUE2,
  VALUE3
}

// names will be equal to: ['VALUE1', 'VALUE2', 'VALUE3']
var names = EnumValues.getNames(SomeEnum);

// values will be equal to: [0, 1, 2]
var values = EnumValues.getValues(SomeEnum);

3

항목 (키-값 개체 / 쌍) 목록을 가져 오는 한 줄 :

Object.keys(MyEnum).filter(a=>a.match(/^\D/)).map(name=>({name, value: MyEnum[name] as number}));

2
enum MyEnum {
    First, Second, Third, NUM_OF_ENUMS
}

for(int i = 0; i < MyEnum.NUM_OF_ENUMS; ++i) {
    // do whatever you need to do.
}

5
이것은 열거 형이 값을 정의하지 않는 경우에만 작동합니다 (잘 압축되고 증분 됨). 예를 들어 열거 형 값은 "First = 0x1000"또는 "PageNotFound = 404"일 수 있습니다. NUM_OF_ENUMS는 항상 정의 된 가장 큰 값보다 하나 더 크므로 내 예에서는 0x1001 또는 405입니다.
Aku

2

열거 형에 문자열 값을 연결하려는 경우 이러한 메서드가 작동하지 않습니다. 일반적인 기능을 사용하려면 다음을 수행하십시오.

function listEnum(enumClass) {
    var values = [];
    for (var key in enumClass) {
        values.push(enum[key]);
    }
    values.length = values.length / 2;
    return values;
}

TypeScript는 첫 번째 단계에서 키를 추가하고 두 번째 단계에서 값을 추가하기 때문에 작동합니다.

TypeScript에서는 다음과 같습니다.

var listEnums = <T> (enumClass: any): T[]=> {
    var values: T[] = [];
    for (var key in enumClass) {
        values.push(enumClass[key]);
    }
    values.length = values.length / 2;
    return values;
};

var myEnum: TYPE[] = listEnums<TYPE>(TYPE);

1

joe의 대답 은 복잡한 테스트를 만드는 것보다 처음 N 개의 숫자 키에 의존하는 것이 훨씬 더 쉽다는 것을 깨달았습니다.

function getEnumMembers(myEnum): string[]
{
    let members = []
    for(let i:number = 0; true; i++) {
        if(myEnum[i] === undefined) break
        members.push(myEnum[i])
    }

    return members
}

enum Colors {
    Red, Green, Blue
}

console.log(getEnumMembers(myEnum))

4
열거 형에 할당 된 값을 정의 할 수 있고 증분되고 잘 압축 될 필요가 없기 때문에 위험한 가정입니다. 예를 들어 열거 형 또는 400에서 시작하는 HTML 오류 코드 테이블에서 비트 마스크를 보는 것은 드문 일이 아닙니다.
Aku


0

nodejs의 경우 :

const { isNumber } = require('util');

Object.values(EnumObject)
      .filter(val => isNumber(val))
      .map(val => {
         // do your stuff
      })

0

열거 형 반복

이를 위해 문자열 열거 형이 가장 적합합니다. 다음은 그 예입니다.

// This is a string enum
enum MyEnum {
    First = 'First',
    Second = 'Second',
    Third = 'Third',
}

// An enum is a TS concept
// However his MyEnum compiles to JS object:
//  {
//   "First": "First",
//   "Second": "Second",
//   "Third": "Third"
// } 


// Therefore we can get the keys in the following manner:
const keysArray = Object.keys(MyEnum);

for (const key of keysArray) {
    console.log(key)
}
// [LOG]: "First" 
// [LOG]: "Second" 
// [LOG]: "Third" 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.