238

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:

[{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?

AnimaSola
  • 7,146
  • 14
  • 43
  • 62
  • Enums are real objects that exist at runtime. So you are able to reverse the mapping doing something like this: `GoalProgressMeasurements[GoalProgressMeasurements.Completed_Tasks]` to get the enum name. I do not know if that helps. – Diullei Mar 29 '17 at 18:04
  • Can you give a better description to "from our API", maybe give an example of usage – gilamran Mar 29 '17 at 21:26

31 Answers31

149

If you are using ES8

For this case only it will work perfectly fine. It will give you value array of the given enum.

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

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

You will get colorValueArray like 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.

Even this kind of enum will work fine

enum Operation {
    READ,
    WRITE,
    EXECUTE
}

But this solution will not work for Heterogeneous enums like this

enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = "YES",
}
Jai Prak
  • 2,855
  • 4
  • 29
  • 37
  • 17
    Keep in mind that this will yield duplicates. The string value and the numerical value for each element, that is a type `(string | YourEnumType)[]` which is not what you might want in each case. – Christian Ivicevic Oct 16 '19 at 20:55
  • 7
    is it guaranteed that the first half will be the keys and the second half will be the values? any reference? – Neekey Sep 23 '20 at 06:58
  • @zedd45 What exactly are you referring to? The link basically leads to the 846 pages standard document, so it is hard to understand which aspect exactly you think is wrong. – bluenote10 Jan 29 '23 at 17:19
  • I went ahead and removed my comment, as I no longer recall what it was supposed to address back from August of last year. I think perhaps there were some comments about the naming convention of EcmaScript itself, not directly related to TS Enums. – zedd45 Feb 14 '23 at 14:50
  • This is no longer the case in TypeScript v5 – Dorklord May 27 '23 at 00:46
96

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.

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:

// 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));
user8363
  • 1,299
  • 3
  • 13
  • 17
  • 2
    mmm if `enum MyEnum { Part1 = 0, Part2 = 1 }` turns into `{ Part1: 0, Part2: 1, 0: 'Part1', 1: 'Part2' }` then, why when you `console.log(Object.values(MyEnum))` it just only prints 0,1? – Juan José Ramírez Apr 14 '20 at 15:16
  • 1
    @JuanJoséRamírez where do you see that? For me `Object.values(MyEnum)` evaluates to `["Part1", "Part2", 0, 1]` – user8363 Apr 14 '20 at 19:33
  • I just printed `console.log(Object.values(MyEnum))` in my component. I'm using angular, not sure if that's related. I'm not that experienced in TypeScript – Juan José Ramírez Apr 16 '20 at 16:13
  • could the behavior change through different TS versions? – Juan José Ramírez Apr 16 '20 at 16:44
  • 9
    I've been checking the docs https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html and it seems string enums have a different behavior. They do not get a reverse mapping generated at all. In my code, I was using a string enum, not the string in this example. – Juan José Ramírez Apr 16 '20 at 16:50
  • 1
    This can fail with members like `'1e5' = 1`, but that's quite the edge case. – TrueWill Apr 23 '21 at 21:51
48

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

Diullei
  • 11,420
  • 2
  • 27
  • 31
48

Simply this will return an array of enum values:

 Object.values(myEnum);
Gaurav Panwar
  • 974
  • 10
  • 11
  • Because it's doesn t give the right result, check https://stackoverflow.com/a/57266281/3548345 – walox Nov 01 '20 at 07:39
  • @walox, It is giving right result only, the link you gave is not showing correct values. Ideally object.keys will return array of keys and object.values will return array of values. – Gaurav Panwar Feb 09 '21 at 17:41
  • 3
    This is enough if your enum consists of key-string pairs like `enum xxx {create = "create"}` – nonNumericalFloat May 13 '22 at 15:46
35

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

 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, ' ') }))
 }
Manoj Shrestha
  • 4,246
  • 5
  • 47
  • 67
  • 11
    you should filter the keys of type number `Object.keys(GoalProgressMeasurements) .filter(key => typeof GoalProgressMeasurements[key] === 'number') .map(key => ({ id: GoalProgressMeasurements[key], name: key }))` – Salvador Rubio Martinez Apr 25 '18 at 08:51
  • Works perfect for string based enums like: export enum UserRole { STUDENT = 'Estudiante', DIRECTOR = 'Director de carrera', AUTHORITY = 'Autoridad', FINANCIAL = 'Dirección Financiera' } – Juan Rojas Aug 19 '21 at 03:43
23

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.

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.

CMS
  • 3,657
  • 1
  • 27
  • 46
  • Not compatible with IE with front-end (should not support ie is a great answer...but I guess customers). Hoping babel transpires it, but sticking to other approaches since I haven't verified it – TamusJRoyce Sep 25 '20 at 00:30
  • string enum is easy, just do `Object.values(GoalProgressMeasurement)` – CMS Dec 06 '20 at 09:18
18

Thanks to polkovnikov.ph I was finally able to find a solution that would work for most of the use-cases.

Valid solution for the question

type Descripted<T> = {
    [K in keyof T]: {
        readonly id: T[K];
        readonly description: string;
    }
}[keyof T]

/**
 * Helper to produce an array of enum descriptors.
 * @param enumeration Enumeration object.
 * @param separatorRegex Regex that would catch the separator in your enum key.
 */
export function enumToDescriptedArray<T>(enumeration: T, separatorRegex: RegExp = /_/g): Descripted<T>[] {
    return (Object.keys(enumeration) as Array<keyof T>)
        .filter(key => isNaN(Number(key)))
        .filter(key => typeof enumeration[key] === "number" || typeof enumeration[key] === "string")
        .map(key => ({
            id: enumeration[key],
            description: String(key).replace(separatorRegex, ' '),
        }));
}

Example:


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

console.log(enumToDescriptedArray(GoalProgressMeasurements))
// Produces:
/*
[
    {id: 1, description: "Percentage"},
    {id: 2, description: "Numeric Target"},
    {id: 3, description: "Completed Tasks"},
    {id: 4, description: "Average Milestone Progress"},
    {id: 5, description: "Not Measured"}
]
*/

Also, there's a useful util function I use to map the enumeration object to an array of available values it has:

The mapper

type NonFunctional<T> = T extends Function ? never : T;

/**
 * Helper to produce an array of enum values.
 * @param enumeration Enumeration object.
 */
export function enumToArray<T>(enumeration: T): NonFunctional<T[keyof T]>[] {
    return Object.keys(enumeration)
        .filter(key => isNaN(Number(key)))
        .map(key => enumeration[key])
        .filter(val => typeof val === "number" || typeof val === "string");
}

Working use-cases

  • Numeric enum
enum Colors1 {
    WHITE = 0,
    BLACK = 1
}
console.log(Object.values(Colors1)); // ['WHITE', 'BLACK', 0, 1]
console.log(enumToArray(Colors1));   // [0, 1]
  • String enum
enum Colors2 {
    WHITE = "white",
    BLACK = "black"
}
console.log(Object.values(Colors2)); // ['white', 'black']
console.log(enumToArray(Colors2));   // ['white', 'black']
  • Heterogenous enum
enum Colors4 {
    WHITE = "white",
    BLACK = 0
}
console.log(Object.values(Colors4)); // ["BLACK", "white", 0]
console.log(enumToArray(Colors4));   // ["white", 0]
  • Enum merged with a namespace with exported functions

enum Colors3 {
    WHITE = "white",
    BLACK = "black"
}
namespace Colors3 {
    export function fun() {}
}
console.log(Object.values(Colors3)); // ['white', 'black', Function]
console.log(enumToArray(Colors3));   // ['white', 'black']
  • `Object.values` returns properties in same order as `for..in` loop, and `for..in` returns them in arbitrary order. This code can return some arbitrary set of keys and values, depending on platform. – polkovnikov.ph Mar 08 '21 at 17:17
  • @polkovnikov.ph You right, thanks! Now the new implementation is not relying on the order of `Object.values` – Viktor Chernodub Mar 09 '21 at 23:53
  • If it has numeric values, it can also be a heterogenous enum (see documentation), and this implementation will lose `string` values. Also it still doesn't answer original question. – polkovnikov.ph Mar 10 '21 at 04:35
  • Thanks, I tried to improve the answer and added the exact solution for the question. – Viktor Chernodub Mar 11 '21 at 12:11
17
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]);
    }
}
Liam Kernighan
  • 2,335
  • 1
  • 21
  • 24
12

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.

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.

/**
 * 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

let 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.

developer033
  • 24,267
  • 8
  • 82
  • 108
MgSam
  • 12,139
  • 19
  • 64
  • 95
  • Result tested with TS4.6, `objs`: `[ { id: 1, name: 'Rover' }, { id: 'Collie', name: 'Lassie' }, { id: 3, name: 'Fido' }, { id: 'Mutt', name: 'Cody' } ]`, `entries`: `[ [ 'Rover', 1 ], [ 'Lassie', 'Collie' ], [ 'Fido', 3 ], [ 'Cody', 'Mutt' ] ]`, `keys`: `[ 'Rover', 'Lassie', 'Fido', 'Cody' ] `, `values`: `[ 1, 'Collie', 3, 'Mutt' ]` – Pablo LION Aug 10 '22 at 23:45
8

Example to get enum value inside array :

export enum DocumentationTypeEnum {
  GDPR = 'GDPR',
  HELP = 'HELP',
  OTHER = 'OTHER',
  FOOTER = 'FOOTER'
}
const keys = Object.keys(DocumentationTypeEnum);
    
console.log(keys); // Output :  ["GDPR", "HELP", "OTHER", "FOOTER"]
lv_
  • 198
  • 1
  • 8
يعقوب
  • 1,008
  • 13
  • 14
  • How would I get this into a valid type? So instead of `Array` get an Array type that can only hold the key values of the enum. – RogerKint Feb 03 '23 at 09:44
8

Just one line:

Object.entries(GoalProgressMeasurements).map(([key, value]) => ({id: key, value: value}))
  • fails for this https://www.typescriptlang.org/play?#code/KYOwrgtgBAMgggZQCoH0ByBVAsgIQKIBKKA8gGIpICSWeUA3gFBTOyKoBsADCgCJwCaCKAF4oXADRMW8ZCgDM3PoJFQFklq1kBGAKy8BQ0bvXS2KLSgDqePAGkVAdhPMZqC0pVbJAXwbEARgBWwADGAC4AdKBhAE4AlsAAzgAUrujY+ERkFNR4AJQREACGAA7JyQDaANbAAJ7iUABuRQA2YMAAunkiAHxQyXRxACYAXFA19U2t7WPNbcDeeXkMQA enum LAST_NUMBER_OF_TIME { LAST_60_DAYS = 60, LAST_30_DAYS = 30, LAST_15_DAYS = 15, LAST_1_WEEK = 7, LAST_1_DAY = 1, } Object.entries(LAST_NUMBER_OF_TIME).map(([key, value]) => ({id: key, value: value})) – hafiz ali Jul 18 '22 at 10:05
  • @hafizali what is the error? – Roman Kostetskyi Jul 19 '22 at 11:20
  • You will get array of array with combination of keys and values, that is the number of items for array of size 3 will be in total 6 – hafiz ali Jul 19 '22 at 11:27
4

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.

const converted = Object.keys(GoalProgressMeasurements).map(key => {
        return {
            id: GoalProgressMeasurements[key],
            name: key,
        };
    });
VaCool
  • 41
  • 2
  • 3
    Welcome to stackoverflow. When answering questions, its a good idea to explain what your code snippet does. For more info, see here: [answer] – Djensen Jan 22 '20 at 09:02
  • 1
    [Here are a few tips on how to make your answer great](https://stackoverflow.com/help/how-to-answer) – Willie Cheng Jan 22 '20 at 09:05
  • Please consider adding some explanation or details to your answer. While it might answer the question, just adding a piece of code as an answer, doesn't per say help OP or future community members understand the issue or the proposed solution. – Maxim Jan 22 '20 at 10:02
4

Yet another approach using ES8 Object.entries

export enum Weeks {  
    MONDAY = 1,  
    TUESDAY= 2,  
    WEDNESDAY = 3,  
    THURSDAY = 4,  
    FRIDAY = 5,  
    SATURDAY=6,  
    SUNDAY=7,  
}


function convertEnumToArray(){
   const arrayObjects = []            
     // Retrieve key and values using Object.entries() method. 
     for (const [propertyKey, propertyValue] of Object.entries(Weeks)) { 

      // Ignore keys that are not numbers
      if (!Number.isNaN(Number(propertyKey))) {  
        continue;  
      }  

      // Add keys and values to array
      arrayObjects.push({ id: propertyValue, name: propertyKey });  
    }        

  console.log(arrayObjects); 
}

Will produce the following:

[ 
  { id: 1, name: 'MONDAY' },  
  { id: 2, name: 'TUESDAY' },  
  { id: 3, name: 'WEDNESDAY' },  
  { id: 4, name: 'THURSDAY' },  
  { id: 5, name: 'FRIDAY' },  
  { id: 6, name: 'SATURDAY' },  
  { id: 7, name: 'SUNDAY' } 
] 

Shamelessly stolen from this blog

sjokkogutten
  • 2,005
  • 2
  • 21
  • 24
3
export function enumKeys(E: any): string[] {
    return Object.keys(E).filter(k => isNaN(Number(k)));
}

export function enumValues(E: any): string[] | number[] {
    return enumKeys(E).map(k => E[k as any]);
}

Works with both:

enum TestA {
    RED = "red",
    BLUE = "blue"
}

enum TestB {
    ONE = 1,
    TWO = 2
}
Scott P.
  • 1,054
  • 11
  • 12
2

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);
nico
  • 21
  • 1
  • Please put your answer always in context instead of just pasting code. See [here](https://stackoverflow.com/help/how-to-answer) for more details. – gehbiszumeis Dec 12 '19 at 16:20
2

There is a simple solution, So when you run Object.keys(Enum) that gonna give you a Array of Values and Keys, in first slice Values and in the second one keys, so why we don't just return the second slice, this code below works for me.

enum Enum {
   ONE,
   TWO,
   THREE,
   FOUR,
   FIVE,
   SIX,
   SEVEN
}
const keys = Object.keys(Enum); 
console.log(keys.slice(keys.length / 2));
Manoj
  • 2,059
  • 3
  • 12
  • 24
2

I know typescript from just a few months, and the solution below worked for me. Hope it may help someone as well -

export enum ScheduleType {
  Basic = <any>'B',
  Consolidated = <any>'C',
}

scheduleTypes = Object.keys(ScheduleType)
.filter((k, i) => i % 2)
.map((key: any) => {
  return {
    systemValue: key,
    displayValue: ScheduleType[key],
  };
});

It gave the following result - [{displayValue: "Basic", systemValue: "B"}, {displayValue: "Consolidated", systemValue: "C"}]

Gaurav
  • 41
  • 4
2

I would like to discourage using TS Enums in cases where list of enum entries is required.

In runtime Enum is implemented as object, but it works as you expect only in this case:

enum X {
  Z = 'z',
  F = 'f'
};

console.log(Object.values(X))
console.log(Object.keys(X))
>>>
[LOG]: ["z", "f"] 
[LOG]: ["Z", "F"] 

In this case it works with a trap (TS lets you to access value by it's numeric value):

enum X {
  Z,
  F
};

console.log(Object.values(X))
console.log(Object.keys(X))
>>>
[LOG]: ["Z", "F", 0, 1] 
[LOG]: ["0", "1", "Z", "F"] 

So any function you write to loop over Enum will work/fail according to Enum definition. Which is ... not good.

My conclusion: Enum was not designed to be used as an object. Use const instead of enum in case you need to access keys and values collections:

const Enumed = {
    X: 1,
    Y: 2
}

Typescript will control existence of object keys and you will be able to do Object.keys, etc. in safe and consistent way.

Max Ivanov
  • 141
  • 2
  • 3
2

I have solved it, this way. Suppose you have an enum like below

export enum UnitEnum {
  GRAM = 'gm',
  KILOGRAM = 'kg',
  LITRE = 'lt',
  CENTIMETER = 'cm',
  INCH = 'in',
  METER = 'mt',
  KILOMETER = 'km',
}

and, you have a class like this,

export interface Unit {
  Name: string;
  Symbol: string;
}

then you can create a function like below to map heterogenous enums to an object of certain type,

export function getDefaultUnits() {
  const myUnits = Object.entries(UnitEnum).map(x => {
    return { Name: x[0], Symbol: x[1] } as Unit
  })

  console.log(myUnits);

  return myUnits;
}
1
function enumKeys(_enum) {
  const entries = Object.entries(_enum).filter(e => !isNaN(Number(e[0])));
  if (!entries.length) {
    // enum has string values so we can use Object.keys
    return Object.keys(_enum);
  }
  return entries.map(e => e[1]);
}
Rip Ryness
  • 651
  • 1
  • 7
  • 14
1

Let the enum variable be :

 enum EnumName {
      A = 1,
      B = 2
    };

Then the list is :

const list = Object.keys(Enum)
.filter((value => isNaN(Number(value)) === false))
      .map(key => ({ id: key, value: Enum[key] }));

The value of list will be

list = [ 
{ id:1 , value: A },
{ id:2 , value: B },
];
Hakeem P A
  • 19
  • 1
0

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.

0

Since enums with Strings values differ from the ones that have number values it is better to filter nonNumbers from @user8363 solution.

Here is how you can get values from enum either strings, numbers of mixed:

    //Helper
    export const StringIsNotNumber = value => isNaN(Number(value)) === true;
    
    // Turn enum into array
    export function enumToArray(enumme) {
      return Object.keys(enumme)
       .filter(StringIsNotNumber)
       .map(key => enumme[key]);
    }
0

I'm surprised in a TypeScript thread no one gave valid TypeScript function with typing supported. Here's variation of @user8363 solution:

const isStringNumber = (value: string) => isNaN(Number(value)) === false;

function enumToArray<T extends {}>(givenEnum: T) {
  return (Object.keys(givenEnum).filter(isStringNumber) as (keyof T)[]).map(
    (key) => givenEnum[key]
  );
}
Daniel Kmak
  • 18,164
  • 7
  • 66
  • 89
0

I don't think the order can be guaranteed, otherwise it would be easy enough to slice the second half of Object.entries result and map from there.

The only (very minor) issues with the answers above is that

  • there is a lot of unnecessary type conversion between string and number.
  • the entries are iterated twice when a single iteration is just as clean and effective.
type StandardEnum = { [id: string]: number | string; [nu: number]: string;}

function enumToList<T extends StandardEnum> (enm: T) : { id: number; description: string }[] {
    return Object.entries(enm).reduce((accum, kv) => {
        if (typeof kv[1] === 'number') {
            accum.push({ id: kv[1], description: kv[0] })
        }
        return accum
    }, []) // if enum is huge, perhaps pre-allocate with new Array(entries.length / 2), however then push won't work, so tracking an index would also be required
}
Brent
  • 4,611
  • 4
  • 38
  • 55
0

TS:

works ONLY with short (<10 elements) enum

const keys = Object.keys(Enum).filter((el: string) => el.length > 1)
console.log(keys)
  1. Object.keys() will return an array with ['0', '1', '2', 'enumElement1', 'enumElement2', enumElement3']
  2. filter() takes every element and check its length (because of string) and excludes all numbers from resulting array
Ihor
  • 9
  • 1
0

this method based on statement: key of enum can't be a numeric

export const isNumeric = (num?: Value | null): num is number => {
  if (num === undefined || num === null) {
    return false;
  } 
  
  const number = +num;

  if (number - number !== 0) {
    // Discard Infinity and NaN
    return false;
  }

  if (number === num) {
    return true;
  }

  if (typeof num === 'string') {
    return !(number === 0 && num.trim() === '');
  }
  return false;
};

enum En  {
  ewq1 = 1,
  we2 = 'ss',
  sad = 'sad',
}

type TEnum = {
    [id: string]: number | string;
}

export const getEnumValues = <T extends TEnum>(enumerable: T) =>
  Object.keys(enumerable)
    .filter((x) => !isNumeric(x))
    .map((key) => enumerable[key] as T[keyof T]) 

console.log(getEnumValues(En)) // [1, "ss", "sad"] 
GoodTrip
  • 26
  • 3
0

another way is

export const GoalNames = {
    [GoalProgressMeasurements.Percentage] = 'Percentage',
    [GoalProgressMeasurements.Numeric_Target] = 'Numeric Target',
    [GoalProgressMeasurements.Completed_Tasks] = 'Completed Tasks',
    [GoalProgressMeasurements.Average_Milestone_Progress] = 'Average Milestone Progress',
    [GoalProgressMeasurements.Not_Measured] = 'Not Measured'
}

and you can call:

const name = GoalNames[goalEnumVal];
Jaider
  • 14,268
  • 5
  • 75
  • 82
0

I solved this way

        const listKeys = Object.keys(TripStatus); //TripStatus is enum type
        const numOfItem = listKeys.length/2;
        for(let i=0; i<numOfItem; i++){
          this.listStatus.push({
            id: listKeys[i],
            name: listKeys[numOfItem+i]
          })
        }
ashiqs
  • 91
  • 4
0
 this worked for me :

    export enum FeedBackType {
    FEEDBACK1= 'FEEDBACK1',
    FEEDBACK2= 'FEEDBACK2',
    FEEDBACK3= 'FEEDBACK3',
    }

----------------------------------------------------------------- 
    export function getTypeFeedBackList() {
    let feedbackList: FeedBackType[] = [];
    Object.keys(FeedBackType).map((key) => {
    let strEnum = key as unknown as FeedBackType;
    feedbackList.push(strEnum);
    });
    return feedbackList;
    }
---------------------------------------------------------------- 
declare this :

    public feedbackList: FeedBackType[] = [];

and after call your function in  :

    ngOnInit(): void {
    this.feedbackList = getTypeFeedBackList();
    console.log(this.feedbackList); 
    }

Happy coding ;) 
0

I like @Hakeem P A's answer's approach but it can be simplified quite a bit.

export enum MediaTypes {
    IMAGE = 1,
    AUDIO = 2,
    VIDEO = 3
}

To convert to an array of objects for something like binding to a select element options in Angular:

types = Object.entries(MediaTypes).filter(([key, val]) => typeof val === 'number').map(([key, val]) => ({ id: val, code: key }));

And then some form markup would look like:

<select name="media-type" [(ngModel)]="media.typeID" required>
    <option [ngValue]="null">&ndash;SELECT MEDIA TYPE&ndash;</option>
    <option [ngValue]="type.id" *ngFor="let type of types">{{type.code}}</option>
</select>
TaeKwonJoe
  • 1,077
  • 11
  • 24