Javascript TypeScript 枚举到对象数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43100718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:40:40  来源:igfitidea点击:

TypeScript enum to object array

javascriptarraystypescriptenumscasting

提问by AnimaSola

I have an enum defined this way:

我有一个这样定义的枚举:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

However, I'd like it to be represented as an object array/list from our API like below:

但是,我希望将其表示为来自我们 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'}]

Is there are easy and native way to do this or do I have to build a function that casts the enum to both an int and a string, and build the objects into an array?

有没有简单的本地方法来做到这一点,或者我是否必须构建一个将枚举转换为 int 和 string 的函数,并将对象构建到一个数组中?

回答by user8363

A tricky bit is that TypeScript will 'double' map the enum in the emitted object, so it can be accessed both by key and value.

一个棘手的问题是 TypeScript 会在发出的对象中“加倍”映射枚举,因此可以通过键和值访问它。

enum MyEnum {
    Part1 = 0,
    Part2 = 1
}

will be emitted as

将被发射为

{
   Part1: 0,
   Part2: 1,
   0: 'Part1',
   1: 'Part2'
}

So you should filter the object first before mapping. So @Diullei 's solution has the right answer. Here is my implementation:

所以你应该在映射之前先过滤对象。所以@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]);
}

Use it like this:

像这样使用它:

export enum GoalProgressMeasurements {
    Percentage,
    Numeric_Target,
    Completed_Tasks,
    Average_Milestone_Progress,
    Not_Measured
}

console.log(ToArray(GoalProgressMeasurements));

回答by Diullei

Enums are real objects that exist at runtime. So you are able to reverse the mapping doing something like this:

枚举是在运行时存在的真实对象。因此,您可以执行以下操作来反转映射:

let value = GoalProgressMeasurements.Not_Measured;
console.log(GoalProgressMeasurements[value]);
// => Not_Measured

Based on that you can use the following code:

基于此,您可以使用以下代码:

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

Reference: https://www.typescriptlang.org/docs/handbook/enums.html

参考:https: //www.typescriptlang.org/docs/handbook/enums.html

回答by Jai Prak

If you are using ES6

如果您使用的是 ES6

It will give you value array of the given enum.

它将为您提供给定enum 的值数组。

enum Colors {
  WHITE = 0,
  BLACK = 1,
  BLUE = 3
}

const colorValueArray = Object.values(Colors); //[ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]

You will get colorValueArraylike this [ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]. All the keys will be in first half of the array and all the values in second half.

你会得到colorValueArray这样的[ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]。所有的键都在数组的前半部分,所有的值在后半部分。

回答by Manoj Shrestha

Easy Solution. You can use the following function to convert your Enum to an array of objects.

简单的解决方案。您可以使用以下函数将 Enum 转换为对象数组。

 buildGoalProgressMeasurementsArray(): Object[] {

    return Object.keys(GoalProgressMeasurements)
              .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
 }

If you needed to strip that underscore off, we could use regex as follows:

如果你需要去掉下划线,我们可以使用正则表达式如下:

buildGoalProgressMeasurementsArray(): Object[] {

    return Object.keys(GoalProgressMeasurements)
              .map(key => ({ id: GoalProgressMeasurements[key], name: key.replace(/_/g, ' ') }))
 }

回答by CMS

I use

我用

Object.entries(GoalProgressMeasurement).filter(e => !isNaN(e[0]as any)).map(e => ({ name: e[1], id: e[0] }));

A simple 1 line that does the job.

一个简单的 1 行就可以完成这项工作。

It does the job in 3 simple steps
- Loads the combination of keys & values using Object.entries.
- Filters out the non numbers (since typescript generates the values for reverse lookup).
- Then we map it to the array object we like.

它通过 3 个简单的步骤完成工作
- 使用Object.entries.
- 过滤掉非数字(因为打字稿生成反向查找的值)。
- 然后我们将它映射到我们喜欢的数组对象。

回答by Liam Kernighan

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

回答by VaCool

First we get an array of keys for this enum. Then, using the map () function, we convert the data to the desired format. id is obtained from the key, name is obtained from enum by the same key.

首先,我们获得此枚举的键数组。然后,使用 map() 函数,我们将数据转换为所需的格式。id 是从key 中获取的,name 是通过相同的key 从enum 中获取的。

const converted = Object.keys(GoalProgressMeasurements).map(key => {
        return {
            id: GoalProgressMeasurements[key],
            name: key,
        };
    });

回答by nico

enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}
    
const array = []
    
for (const [key, value] of Object.entries(GoalProgressMeasurements)) {
    if (!Number.isNaN(Number(key))) {
        continue;
    }

    array.push({ id: value, name: key.replace('_', '') });
}

console.log(array);

回答by MgSam

I didn't like any of the above answers because none of them correctly handle the mixture of strings/numbers that can be values in TypeScript enums.

我不喜欢上述任何一个答案,因为它们都没有正确处理可以是 TypeScript 枚举中的值的字符串/数字的混合。

The following function follows the semantics of TypeScript enums to give a proper Map of keys to values. From there, getting an array of objects or just the keys or just the values is trivial.

以下函数遵循 TypeScript 枚举的语义,以提供适当的键值映射。从那里,获取对象数组或仅键或仅值是微不足道的。

/**
 * Converts the given enum to a map of the keys to the values.
 * @param enumeration The enum to convert to a map.
 */
function enumToMap(enumeration: any): Map<string, string | number> {
  const map = new Map<string, string | number>();
  for (let key in enumeration) {
      //TypeScript does not allow enum keys to be numeric
      if (!isNaN(Number(key))) continue;

      const val = enumeration[key] as string | number;

      //TypeScript does not allow enum value to be null or undefined
      if (val !== undefined && val !== null)
          map.set(key, val);
  }

  return map;
}

Example Usage:

示例用法:

enum Dog {
    Rover = 1,
    Lassie = "Collie",
    Fido = 3,
    Cody = "Mutt",
}

let map = enumToMap(Dog); //Map of keys to values

lets objs = Array.from(map.entries()).map(m => ({id: m[1], name: m[0]})); //Objects as asked for in OP
let entries = Array.from(map.entries()); //Array of each entry
let keys = Array.from(map.keys()); //An array of keys
let values = Array.from(map.values()); //An array of values

I'll also point out that the OP is thinking of enums backwards. The "key" in the enum is technically on the left hand side and the value is on the right hand side. TypeScript allows you to repeat the values on the RHS as much as you'd like.

我还要指出,OP 正在向后考虑枚举。枚举中的“键”在技术上位于左侧,而值位于右侧。TypeScript 允许您根据需要重复 RHS 上的值。

回答by Boban Stojanovski

You can do that in this way:

你可以这样做:

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"),
}

And you can use it like this:

你可以像这样使用它:

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;

You can extend the GoalProgressMeasurement with additional properties of the object as you need. I'm using this approach for every enumeration that should be an object containing more then a value.

您可以根据需要使用对象的其他属性扩展 GoalProgressMeasurement。对于应该是包含多个值的对象的每个枚举,我都使用这种方法。