TypeScript перечисление в массив объектов
У меня есть перечисление, определенное следующим образом:
export enum GoalProgressMeasurements {
Percentage = 1,
Numeric_Target = 2,
Completed_Tasks = 3,
Average_Milestone_Progress = 4,
Not_Measured = 5
}
Однако я хотел бы, чтобы он был представлен как массив объектов/список из нашего API, как показано ниже:
[{id: 1, name: 'Percentage'},
{id: 2, name: 'Numeric Target'},
{id: 3, name: 'Completed Tasks'},
{id: 4, name: 'Average Milestone Progress'},
{id: 5, name: 'Not Measured'}]
Есть ли простой и естественный способ сделать это или мне нужно создать функцию, которая передает перечисление как для int, так и для строки, и построить объекты в массив?
Ответы
Ответ 1
Перечисления - это реальные объекты, которые существуют во время выполнения. Таким образом, вы можете изменить отображение, сделав что-то вроде этого:
let value = GoalProgressMeasurements.Not_Measured;
console.log(GoalProgressMeasurements[value]);
// => Not_Measured
На основании этого вы можете использовать следующий код:
export enum GoalProgressMeasurements {
Percentage = 1,
Numeric_Target = 2,
Completed_Tasks = 3,
Average_Milestone_Progress = 4,
Not_Measured = 5
}
let map: {id: number; name: string}[] = [];
for(var n in GoalProgressMeasurements) {
if (typeof GoalProgressMeasurements[n] === 'number') {
map.push({id: <any>GoalProgressMeasurements[n], name: n});
}
}
console.log(map);
Ссылка: https://www.typescriptlang.org/docs/handbook/enums.html
Ответ 2
Хитрость заключается в том, что TypeScript "удвоит" отображение перечисления в излучаемом объекте, поэтому к нему можно получить доступ как по ключу, так и по значению.
enum MyEnum {
Part1 = 0,
Part2 = 1
}
будет выпущен как
{
Part1: 0,
Part2: 1,
0: 'Part1',
1: 'Part2'
}
Поэтому вы должны сначала отфильтровать объект перед отображением. Так что решение @Diullei имеет правильный ответ. Вот моя реализация:
// Helper
const StringIsNumber = value => isNaN(Number(value)) === false;
// Turn enum into array
function ToArray(enumme) {
return Object.keys(enumme)
.filter(StringIsNumber)
.map(key => enumme[key]);
}
Используйте это так:
export enum GoalProgressMeasurements {
Percentage,
Numeric_Target,
Completed_Tasks,
Average_Milestone_Progress,
Not_Measured
}
console.log(ToArray(GoalProgressMeasurements));
Ответ 3
Простое решение. Вы можете использовать следующую функцию для преобразования вашего Enum в массив объектов.
buildGoalProgressMeasurementsArray(): Object[] {
return Object.keys(GoalProgressMeasurements)
.map(key => ({ id: GoalProgressMeasurements[key], name: key }))
}
Если вам нужно снять это подчеркивание, мы можем использовать регулярное выражение следующим образом:
buildGoalProgressMeasurementsArray(): Object[] {
return Object.keys(GoalProgressMeasurements)
.map(key => ({ id: GoalProgressMeasurements[key], name: key.replace(/_/g, ' ') }))
}
Ответ 4
Если вы используете ES6
Это даст вам массив значений заданного перечисления.
enum colors = {
"WHITE" : 0,
"BLACK" : 1
}
const colorValueArray = Object.values(colors);
Ответ 5
class EnumHelpers {
static getNamesAndValues<T extends number>(e: any) {
return EnumHelpers.getNames(e).map(n => ({ name: n, value: e[n] as T }));
}
static getNames(e: any) {
return EnumHelpers.getObjValues(e).filter(v => typeof v === 'string') as string[];
}
static getValues<T extends number>(e: any) {
return EnumHelpers.getObjValues(e).filter(v => typeof v === 'number') as T[];
}
static getSelectList<T extends number, U>(e: any, stringConverter: (arg: U) => string) {
const selectList = new Map<T, string>();
this.getValues(e).forEach(val => selectList.set(val as T, stringConverter(val as unknown as U)));
return selectList;
}
static getSelectListAsArray<T extends number, U>(e: any, stringConverter: (arg: U) => string) {
return Array.from(this.getSelectList(e, stringConverter), value => ({ value: value[0] as T, presentation: value[1] }));
}
private static getObjValues(e: any): (number | string)[] {
return Object.keys(e).map(k => e[k]);
}
}
Ответ 6
Вы можете сделать это следующим образом:
export enum GoalProgressMeasurements {
Percentage = 1,
Numeric_Target = 2,
Completed_Tasks = 3,
Average_Milestone_Progress = 4,
Not_Measured = 5
}
export class GoalProgressMeasurement {
constructor(public goalProgressMeasurement: GoalProgressMeasurements, public name: string) {
}
}
export var goalProgressMeasurements: { [key: number]: GoalProgressMeasurement } = {
1: new GoalProgressMeasurement(GoalProgressMeasurements.Percentage, "Percentage"),
2: new GoalProgressMeasurement(GoalProgressMeasurements.Numeric_Target, "Numeric Target"),
3: new GoalProgressMeasurement(GoalProgressMeasurements.Completed_Tasks, "Completed Tasks"),
4: new GoalProgressMeasurement(GoalProgressMeasurements.Average_Milestone_Progress, "Average Milestone Progress"),
5: new GoalProgressMeasurement(GoalProgressMeasurements.Not_Measured, "Not Measured"),
}
И вы можете использовать это так:
var gpm: GoalProgressMeasurement = goalProgressMeasurements[GoalProgressMeasurements.Percentage];
var gpmName: string = gpm.name;
var myProgressId: number = 1; // the value can come out of drop down selected value or from back-end , so you can imagine the way of using
var gpm2: GoalProgressMeasurement = goalProgressMeasurements[myProgressId];
var gpmName: string = gpm.name;
Вы можете расширить GoalProgressMeasurement дополнительными свойствами объекта по мере необходимости. Я использую этот подход для каждого перечисления, которое должно быть объектом, содержащим больше, чем значение.