Подтвердить что ты не робот

Как программно перечислить тип enum?

Скажем, у меня есть enum TypeScript, 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?
4b9b3361

Ответ 1

Это выход JavaScript этого перечисления:

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

Что такое объект:

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

Имена участников

Чтобы получить имена членов перечисления, мы можем отфильтровать ключи объектов, когда соответствующее значение является числом. При этом будут найдены имена с одинаковым значением:

const names = Object.keys(MyEnum)
    .filter(k => typeof MyEnum[k] === "number") as string[];

Содержит: ["First", "Second", "Third"]

Ценности участника

Чтобы получить значения элемента перечисления, мы можем отфильтровать значения объектов на все, что является числом:

const values = Object.keys(MyEnum)
    .map(k => MyEnum[k])
    .filter(v => typeof v === "number") as number[];

Содержит: [0, 1, 2]

Класс расширения

Я думаю, что лучший способ сделать это - создать свои собственные функции (например, EnumEx.getNames(MyEnum)). Вы не можете добавить функцию к перечислению.

class EnumEx {
    private constructor() {
    }

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

    static getNames(e: any) {
        return Object.keys(e).filter(k => typeof e[k] === "number") as string[];
    }

    static getValues<T extends number>(e: any) {
        return Object.keys(e)
            .map(k => e[k])
            .filter(v => typeof v === "number") as T[];
    }
}

Ответ 2

С TypeScript> = 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);
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
*/

Смотрите онлайн { 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 */ rel=noreferrer>пример на игровой площадке TypeScript

(*) Polyfill необходим для старых браузеров, см. Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values#Browser_compatibility

Ответ 3

Существует нет понятия RTTI (информация о типе времени выполнения) в TypeScript (think: reflection), поэтому для этого требуется знание переписанного 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";
}

Таким образом, это моделируется как обычный объект в javascript, где 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. Использование перечислений таким образом не сохраняет эту цель.

Ответ 4

Вы можете добавлять функции для получения имен и индексов перечисления:

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 генерировал нечто подобное автоматически для всех перечислений.

Ответ 5

Я использовал решение, предложенное Дэвидом Шерретом и написал библиотеку npm, которую вы можете использовать с именем enum-values...

Git: перечисляемые значения

// 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);

Ответ 6

enum MyEnum {
    First, Second, Third, NUM_OF_ENUMS
}

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

Ответ 7

Если вы хотите связать значения строк с вашим перечислением, эти методы не работают. Чтобы получить общую функцию, которую вы можете сделать:

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);

Ответ 8

Один-линейный, чтобы получить список записей (объекты/пары с ключом):

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

Ответ 9

joe answer просто заставило меня понять, что гораздо проще использовать первые 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))