Как программно перечислить тип 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?
Ответы
Ответ 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))