How to get names of enum entries?
Asked Answered
A

44

699

I would like to iterate a TypeScript enum object and get each enumerated symbol name, for example: enum myEnum { entry1, entry2 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}
Armbruster answered 7/8, 2013 at 19:1 Comment(4)
this tiny enum-for package has getAllEnumValues and getAllEnumKeys for your purposeSewoll
I have created a PR (issue) to add native support for for (const [name, value] of MyEnum) { to Typescript. Hopefully this will be easier one day!Otherworldly
Must have been to difficult to provide a EnumType.name() method.Delvalle
I found this article useful technicalfeeder.com/2021/07/mastering-enum-in-typescriptMicahmicawber
B
381

The code you posted will work; it will print out all the members of the enum, including the values of the enum members. For example, the following code:

enum myEnum { bar, foo }

for (var enumMember in myEnum) {
   console.log("enum member: ", enumMember);
}

Will print the following:

Enum member: 0
Enum member: 1
Enum member: bar
Enum member: foo

If you instead want only the member names, and not the values, you could do something like this:

for (var enumMember in myEnum) {
   var isValueProperty = Number(enumMember) >= 0
   if (isValueProperty) {
      console.log("enum member: ", myEnum[enumMember]);
   }
}

That will print out just the names:

Enum member: bar  
Enum member: foo

Caveat: this slightly relies on an implementation detail: TypeScript compiles enums to a JS object with the enum values being members of the object. If TS decided to implement them different in the future, the above technique could break.

Bellabelladonna answered 7/8, 2013 at 19:30 Comment(4)
To be clear, the above answer still works as of TS 2.3. However, if you use "const enum", rather than just "enum", only then will it not work. Using const enum is basically telling TS to do a search-and-replace; every place you use MyEnum.Foo, it will be replaced with a corresponding numeric value.Bellabelladonna
I think the +enumMember >= 0 should be isFinite(+enumMember) because negative or floating point values get reverse mapped too. (Playground)Telekinesis
Enum entries can be string with leading zeros like 00111, you need to exclude these tooCrafty
As of TS 4, doesn't work with numeric and heterogenous enums.Gulick
H
847

Though the answer is already provided, Almost no one pointed to the docs

Here's a snippet

enum SampleEnum {
    A,
     
}
let nameOfA = SampleEnum[SampleEnum.A]; // "A"

Keep in mind that string enum members do not get a reverse mapping generated at all.

Huntingdonshire answered 11/2, 2017 at 4:42 Comment(8)
How about displaying 0 or 1 from this enum ? export enum Octave { ZERO = 0, ONE = 1 }Gudrunguelderrose
@jbojcic Is it about situation: enum Enum {"A"}; let nameOfA = Enum[Enum.A];? As of [email protected] it works fine for me...Croy
How about looping through values?Michaels
In JS enum is an object of [value]: name so you can get all values like that Object.keys(enum), all names Object.values(enum) and iterate in one go using for(const [value, name] of Object.entries(enum)) { ... }. Beware that when you get values they will be strings, not numbers as you would expect (since in JS keys of object are strings).Marjorymarjy
I don't see how this answers the question that was asked. Yes, the facts stated here are correct, and one could deduce an answer from it, but there is no direct answer.Colecolectomy
Odd how you can't use this to call a static property of a class... Having class S { static SP = 1 } and enum E { SP }, you can call E[E.SP] // "SP" and S["SP"], but not S[E[E.SP]].Hiroko
Would be more clear if you name the enum something other than EnumShanahan
let filteredKeys = Object.entries(AnimalEnum).filter(([,value]) => value === AnimalEnum.DOG || value === AnimalEnum.CAT).map(([key,]) => { return key })Textbook
B
381

The code you posted will work; it will print out all the members of the enum, including the values of the enum members. For example, the following code:

enum myEnum { bar, foo }

for (var enumMember in myEnum) {
   console.log("enum member: ", enumMember);
}

Will print the following:

Enum member: 0
Enum member: 1
Enum member: bar
Enum member: foo

If you instead want only the member names, and not the values, you could do something like this:

for (var enumMember in myEnum) {
   var isValueProperty = Number(enumMember) >= 0
   if (isValueProperty) {
      console.log("enum member: ", myEnum[enumMember]);
   }
}

That will print out just the names:

Enum member: bar  
Enum member: foo

Caveat: this slightly relies on an implementation detail: TypeScript compiles enums to a JS object with the enum values being members of the object. If TS decided to implement them different in the future, the above technique could break.

Bellabelladonna answered 7/8, 2013 at 19:30 Comment(4)
To be clear, the above answer still works as of TS 2.3. However, if you use "const enum", rather than just "enum", only then will it not work. Using const enum is basically telling TS to do a search-and-replace; every place you use MyEnum.Foo, it will be replaced with a corresponding numeric value.Bellabelladonna
I think the +enumMember >= 0 should be isFinite(+enumMember) because negative or floating point values get reverse mapped too. (Playground)Telekinesis
Enum entries can be string with leading zeros like 00111, you need to exclude these tooCrafty
As of TS 4, doesn't work with numeric and heterogenous enums.Gulick
C
135

For me an easier, practical and direct way to understand what is going on, is that the following enumeration:

enum colors { red, green, blue };

Will be converted essentially to this:

var colors = { red: 0, green: 1, blue: 2,
               [0]: "red", [1]: "green", [2]: "blue" }

Because of this, the following will be true:

colors.red === 0
colors[colors.red] === "red"
colors["red"] === 0

This creates a easy way to get the name of an enumerated as follows:

var color: colors = colors.red;
console.log("The color selected is " + colors[color]);

It also creates a nice way to convert a string to an enumerated value.

var colorName: string = "green";
var color: colors = colors.red;
if (colorName in colors) color = colors[colorName];

The two situations above are far more common situation, because usually you are far more interested in the name of a specific value and serializing values in a generic way.

Comitia answered 11/9, 2016 at 18:52 Comment(2)
This is a nice description of how TS enums work, but doesn't answer the question of how to "iterate" over "each enumerated symbol name".Gulick
Best example so far of how enums work! Thank you.Hike
E
105

If you only search for the names and iterate later use:

Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];
Entremets answered 29/3, 2017 at 11:2 Comment(7)
Or with the ES2017 lib: Object.values(myEnum).filter(value => typeof value === 'string') as string[];Indigent
I needed to create a dict, and I used your answer as a startpoint. If someone else needs it, Object.values(myEnum).filter(value => typeof value === 'string').map(key => { return {id: myEnum[key], type: key }; });Squirm
or just Object.values(myEnum).filter(isNaN) as string[];Denison
Isn't Object.keys(myEnum) enough to get an array with of key names in an enum object?Hanuman
best way so far is Object.entries(temp1).splice(Object.keys(temp1).length/2) so we get the entriesLepido
For enum Test1 { A = "C", B = "D"} returns ["C", "D"]. That's values, not keys.Gulick
@BrunoNegrãoZica Object.keys(myEnum) returns not only string keys of enum but also theis corresponding index in enum. Like ts enum Color { Black, White } console.log(Object.keys(Color)) // '0', '1', 'Black', 'White' Danikadanila
B
64

Assuming you stick to the rules and only produce enums with numeric values, you can use this code. This correctly handles the case where you have a name that is coincidentally a valid number

enum Color {
    Red,
    Green,
    Blue,
    "10" // wat
}

var names: string[] = [];
for(var n in Color) {
    if(typeof Color[n] === 'number') names.push(n);
}
console.log(names); // ['Red', 'Green', 'Blue', '10']
Baudekin answered 7/8, 2013 at 19:46 Comment(2)
Warning In modern typescript (tsc 2.5.2 atm) you are not even allowed to have a numeric string as a key to begin with. As such Himango's answer is better, since it covers all cases and has no downsides.Caiman
Object.prototype.foo = 1;Gulick
C
52

It seems that none of the answers here will work with string-enums in strict-mode.

Consider enum as:

enum AnimalEnum {
  dog = "dog", cat = "cat", mouse = "mouse"
}

Accessing this with AnimalEnum["dog"] may result in an error like:

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof AnimalEnum'.ts(7053).

Proper solution for that case, write it as:

AnimalEnum["dog" as keyof typeof AnimalEnum]
Corpse answered 20/3, 2020 at 14:22 Comment(5)
Brilliant solution for using the keyof with typeof! Other solution seems pretty opaque, but after all I think Typescript needs to keep improve on DX - Developer Experience for EnumCorcovado
Not so brilliant when the value is not the same as the keyHanoi
This solution is good when you want to map enum values when passed a key,Furor
This solution was so minimal, yet worked perfectly for my purposes. Excellent work! I used this in a map function for an api response. Much simpler than iterating though the object values or keys and working back from there. Very much appreciated!Wandis
This is what I was looking for, thanks!Silicify
B
33

As of TypeScript 2.4, enums can contain string intializers https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html

This allows you to write:

 enum Order {
      ONE = "First",
      TWO = "Second"
 }

console.log(`One is ${Order.ONE.toString()}`);

and get this output:

One is First

Bohemianism answered 13/8, 2018 at 15:53 Comment(1)
How does it "iterate" over "each enumerated symbol name"? This is not an answer to the given question at all.Gulick
F
32

With current TypeScript Version 1.8.9 I use typed Enums:

export enum Option {
    OPTION1 = <any>'this is option 1',
    OPTION2 = <any>'this is option 2'
}

with results in this Javascript object:

Option = {
    "OPTION1": "this is option 1",
    "OPTION2": "this is option 2",
    "this is option 1": "OPTION1",
    "this is option 2": "OPTION2"
}

so I have to query through keys and values and only return values:

let optionNames: Array<any> = [];    
for (let enumValue in Option) {
    let optionNameLength = optionNames.length;

    if (optionNameLength === 0) {
        this.optionNames.push([enumValue, Option[enumValue]]);
    } else {
        if (this.optionNames[optionNameLength - 1][1] !== enumValue) {
            this.optionNames.push([enumValue, Option[enumValue]]);
        }
    }
}

And I receive the option keys in an Array:

optionNames = [ "OPTION1", "OPTION2" ];
Fretwell answered 11/4, 2016 at 10:17 Comment(3)
well, code says different thing, you will get: optionNames = [["OPTION1", "this is option 1"], ["OPTION2", "this is option 2"]], but overall I appreciate your idea of removing double reversed entries, everyone else here considers that value is always a numberMichal
@DimaKaraush Not everyone. Also this answer relies on order of keys in objects, and is blatantly wrong.Gulick
After fixing issues with the code, it produces [["OPTION1", "this is option 1"], ["OPTION2", "this is option 2"]] instead. Even if you take first element of each of those tuples, it fails on enum Test2 { A, B } by producing ["0", "1", "A", "B"].Gulick
U
30

This solution work too.

enum ScreenType {
    Edit = 1,
    New = 2,
    View = 4
}

var type: ScreenType = ScreenType.Edit;

console.log(ScreenType[type]); //Edit
Undoing answered 9/10, 2017 at 18:25 Comment(3)
Why it prints 'undefined' for me? Any idea?Reformed
How does it "iterate" over "each enumerated symbol name"? This is not an answer to the given question at all.Gulick
While you show how to access enums with its array accessor, I recommend adding the iteration part to answer the questionInarticulate
U
28

In a nutshell

if your enums is as below:

export enum Colors1 {
  Red = 1,
  Green = 2,
  Blue = 3
}

to get specific text and value:

console.log(Colors1.Red); // 1 
console.log(Colors1[Colors1.Red]); // Red

to get list of value and text:

public getTextAndValues(e: { [s: number]: string }) {
  for (const enumMember in e) {
    if (parseInt(enumMember, 10) >= 0) {
      console.log(e[enumMember]) // Value, such as 1,2,3
      console.log(parseInt(enumMember, 10)) // Text, such as Red,Green,Blue
    }
  }
}
this.getTextAndValues(Colors1)

if your enums is as below:

export enum Colors2 {
  Red = "Red",
  Green = "Green",
  Blue = "Blue"
}

to get specific text and value:

console.log(Colors2.Red); // Red
console.log(Colors2["Red"]); // Red

to get list of value and text:

public getTextAndValues(e: { [s: string]: string }) {
  for (const enumMember in e) {
    console.log(e[enumMember]);// Value, such as Red,Green,Blue
    console.log(enumMember); //  Text, such as Red,Green,Blue
  }
}
this.getTextAndValues(Colors2)
Ulani answered 19/12, 2020 at 8:58 Comment(3)
Doesn't work with string and heterogenous enums. By the look of thsi it's easy to imply the code wasn't ever compiled.Gulick
@polkovnikov.ph- I updated my answer, in my opinion, you should not downvote a question because of the Writing errorUlani
I downvoted it, because it's wrong. Numeric enums are not the only type of enums. Also I don't see why numbers have to be non-negative. enum A { B = -1 } is perfectly valid.Gulick
M
18

Another interesting solution found here is using ES6 Map:

export enum Type {
  low,
  mid,
  high
}

export const TypeLabel = new Map<number, string>([
  [Type.low, 'Low Season'],
  [Type.mid, 'Mid Season'],
  [Type.high, 'High Season']
]);

USE

console.log(TypeLabel.get(Type.low)); // Low Season


TypeLabel.forEach((label, value) => {
  console.log(label, value);
});

// Low Season 0
// Mid Season 1
// High Season 2    
Margo answered 12/3, 2019 at 14:6 Comment(3)
The question asked how to "iterate" over enum's keys. This doesn't answer the question.Gulick
I added an example showing how to iterate the mapMargo
Unfortunately, it's wrong. enum Test { A = 0 }Gulick
C
16

Let ts-enum-util (github, npm) do the work for you and provide a lot of additional type-safe utilities. Works with both string and numeric enums, properly ignoring the numeric index reverse lookup entries for numeric enums:

String enum:

import {$enum} from "ts-enum-util";

enum Option {
    OPTION1 = 'this is option 1',
    OPTION2 = 'this is option 2'
}

// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();

// type: Option[]
// value: ["this is option 1", "this is option 2"]
const values = $enum(Option).getValues();

Numeric enum:

enum Option {
    OPTION1,
    OPTION2
}

// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();

// type: Option[]
// value: [0, 1]
const values = $enum(Option).getValues();
Collier answered 24/2, 2018 at 6:0 Comment(4)
Looks bugged. Code doesn't distinguish between "0" and 0. Also, size of the library is ridiculous.Gulick
@Gulick - Could you give more detail or an example of where the code fails to distinguish between "0" and 0? And about the size of the library, are you just looking at the total size of the NPM package? The size of the raw code itself is pretty small. Most of the package size is documentation (code comments and markdown files), and the fully documented source code is included with source maps for debugging.Collier
For enum Test { NaN = 'LOL' } it produces [].Gulick
Also it takes over 1700 lines of code for something that should take 5.Gulick
G
16

I got tired looking through incorrect answers, and did it myself.

  • THIS ONE HAS TESTS.
  • Works with all types of enumerations.
  • Correctly typed.
type EnumKeys<Enum> = Exclude<keyof Enum, number>

const enumObject = <Enum extends Record<string, number | string>>(e: Enum) => {
    const copy = {...e} as { [K in EnumKeys<Enum>]: Enum[K] };
    Object.values(e).forEach(value => typeof value === 'number' && delete copy[value]);
    return copy;
};

const enumKeys = <Enum extends Record<string, number | string>>(e: Enum) => {
    return Object.keys(enumObject(e)) as EnumKeys<Enum>[];
};

const enumValues = <Enum extends Record<string, number | string>>(e: Enum) => {
    return [...new Set(Object.values(enumObject(e)))] as Enum[EnumKeys<Enum>][];
};

enum Test1 { A = "C", B = "D"}
enum Test2 { A, B }
enum Test3 { A = 0, B = "C" }
enum Test4 { A = "0", B = "C" }
enum Test5 { undefined = "A" }
enum Test6 { A = "undefined" }
enum Test7 { A, B = "A" }
enum Test8 { A = "A", B = "A" }
enum Test9 { A = "B", B = "A" }

console.log(enumObject(Test1)); // {A: "C", B: "D"}
console.log(enumObject(Test2)); // {A: 0, B: 1}
console.log(enumObject(Test3)); // {A: 0, B: "C"}
console.log(enumObject(Test4)); // {A: "0", B: "C"}
console.log(enumObject(Test5)); // {undefined: "A"}
console.log(enumObject(Test6)); // {A: "undefined"}
console.log(enumObject(Test7)); // {A: 0,B: "A"}
console.log(enumObject(Test8)); // {A: "A", B: "A"}
console.log(enumObject(Test9)); // {A: "B", B: "A"}

console.log(enumKeys(Test1)); // ["A", "B"]
console.log(enumKeys(Test2)); // ["A", "B"]
console.log(enumKeys(Test3)); // ["A", "B"]
console.log(enumKeys(Test4)); // ["A", "B"]
console.log(enumKeys(Test5)); // ["undefined"]
console.log(enumKeys(Test6)); // ["A"]
console.log(enumKeys(Test7)); // ["A", "B"]
console.log(enumKeys(Test8)); // ["A", "B"]
console.log(enumKeys(Test9)); // ["A", "B"]

console.log(enumValues(Test1)); // ["C", "D"]
console.log(enumValues(Test2)); // [0, 1]
console.log(enumValues(Test3)); // [0, "C"]
console.log(enumValues(Test4)); // ["0", "C"]
console.log(enumValues(Test5)); // ["A"] 
console.log(enumValues(Test6)); // ["undefined"] 
console.log(enumValues(Test7)); // [0, "A"]
console.log(enumValues(Test8)); // ["A"]
console.log(enumValues(Test9)); // ["B", "A"]

Online version.

Gulick answered 8/3, 2021 at 17:1 Comment(0)
S
15

In TypeScript, an enum is compiled to a map (to get the value from the key) in javascript:

enum MyEnum {
  entry0,
  entry1,
}

console.log(MyEnum['entry0']); // 0
console.log(MyEnum['entry1']); // 1

It also creates a reversed map (to get the key from the value):

console.log(MyEnum[0]); // 'entry0'
console.log(MyEnum[0]); // 'entry1'

So you can access the name of an entry by doing:

console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'

However, string enum has no reverse map by design (see comment and pull request) because this could lead to conflict between keys and values in the map object.

enum MyEnum {
  entry0 = 'value0',
  entry1 = 'value1',
}

console.log(MyEnum['value0']); // undefined
console.log(MyEnum['value1']); // undefined

If you want to force your string enum to compile a reversed map (you then have to make sure all the keys and values are different), you can use this trick:

enum MyEnum {
  entry0 = <any>'value0',
  entry1 = <any>'value1',
}

console.log(MyEnum['value0']); // 'entry0'
console.log(MyEnum['value1']); // 'entry1'
console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'
Styles answered 6/1, 2022 at 17:56 Comment(1)
Nicely covered theory! The question asked for "get each enumerated symbol name" though.Gulick
B
13

Assume you have an enum

export enum SCROLL_LABEL_OFFSET {
  SMALL = 48,
  REGULAR = 60,
  LARGE = 112
}

and you want to create a type based on enum but not just copy and paste. You could use an enum to create your type like this:

export type ScrollLabelOffset = keyof typeof SCROLL_LABEL_OFFSET;

In result you will receive a type with possible values as 'SMALL' | 'REGULAR' | 'LARGE'

Brandabrandais answered 14/9, 2021 at 14:16 Comment(1)
But the question asked for a value, not for a type.Gulick
G
9

Starting from TypeScript 2.4, the enum would not contain the key as a member anymore. source from TypeScript readme

The caveat is that string-initialized enums can't be reverse-mapped to get the original enum member name. In other words, you can't write Colors["RED"] to get the string "Red".

My solution:

export const getColourKey = (value: string ) => {
    let colourKey = '';
    for (const key in ColourEnum) {
        if (value === ColourEnum[key]) {
            colourKey = key;
            break;
        }
    }
    return colourKey;
};
Groupie answered 25/1, 2018 at 7:55 Comment(1)
Question asked for "get each enumerated symbol name". This finds a specific key by value.Gulick
M
7

Based on some answers above I came up with this type-safe function signature:

export function getStringValuesFromEnum<T>(myEnum: T): (keyof T)[] {
  return Object.keys(myEnum).filter(k => typeof (myEnum as any)[k] === 'number') as any;
}

Usage:

enum myEnum { entry1, entry2 };
const stringVals = getStringValuesFromEnum(myEnum);

the type of stringVals is 'entry1' | 'entry2'

See it in action

Murderous answered 18/4, 2018 at 8:13 Comment(2)
The function should return (keyof T)[] instead of keyof T. Also, the export stops your playground from working.Dropsonde
For enum Test1 { A = "C", B = "D" } returns [].Gulick
B
7

They have provided a concept called 'reverse-mapping' in their official documentation. It helped me:

https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings

The solution is quite straight forward:

enum Enum {
 A,
}

let a = Enum.A;
let nameOfA = Enum[a]; // "A"
Bomb answered 9/9, 2021 at 16:37 Comment(2)
This works, but only on numeric enums.Ascidian
Question asked for "get each enumerated symbol name".Gulick
B
6

According to TypeScript documentation, we can do this via Enum with static functions.

Get Enum Name with static functions

enum myEnum { 
    entry1, 
    entry2 
}

namespace myEnum {
    export function GetmyEnumName(m: myEnum) {
      return myEnum[m];
    }
}


now we can call it like below
myEnum.GetmyEnumName(myEnum.entry1);
// result entry1 

for reading more about Enum with static function follow the below link https://basarat.gitbooks.io/typescript/docs/enums.html

Bedford answered 4/9, 2018 at 13:39 Comment(1)
This searches for enum key by value. Question asked for "get each enumerated symbol name".Gulick
A
6

I wrote an EnumUtil class which is making a type check by the enum value:

export class EnumUtils {
  /**
   * Returns the enum keys
   * @param enumObj enum object
   * @param enumType the enum type
   */
  static getEnumKeys(enumObj: any, enumType: EnumType): any[] {
    return EnumUtils.getEnumValues(enumObj, enumType).map(value => enumObj[value]);
  }

  /**
   * Returns the enum values
   * @param enumObj enum object
   * @param enumType the enum type
   */
  static getEnumValues(enumObj: any, enumType: EnumType): any[] {
    return Object.keys(enumObj).filter(key => typeof enumObj[key] === enumType);
  }
}

export enum EnumType {
  Number = 'number',
  String = 'string'
}

How to use it:

enum NumberValueEnum{
  A= 0,
  B= 1
}

enum StringValueEnum{
  A= 'A',
  B= 'B'
}

EnumUtils.getEnumKeys(NumberValueEnum, EnumType.Number);
EnumUtils.getEnumValues(NumberValueEnum, EnumType.Number);

EnumUtils.getEnumKeys(StringValueEnum, EnumType.String);
EnumUtils.getEnumValues(StringValueEnum, EnumType.String);

Result for NumberValueEnum keys: ["A", "B"]

Result for NumberValueEnum values: [0, 1]

Result for StringValueEnumkeys: ["A", "B"]

Result for StringValueEnumvalues: ["A", "B"]

Around answered 4/2, 2019 at 12:47 Comment(2)
Nice! However, I would switch what you define as keys and values. Values should be what's to the right of the equals sign, keys on the leftFayina
How to use with heterogenous enums?Gulick
A
6

There are already a lot of answers here but I figure I'll throw my solution onto the stack anyway.

TypeScript Playground

enum AccountType {
  Google = 'goo',
  Facebook = 'boo',
  Twitter = 'wit',
}

type Key = keyof typeof AccountType // "Google" | "Facebook" | "Twitter"

// this creates a POJO of the enum "reversed" using TypeScript's Record utility
const reversed = (Object.keys(AccountType) as Key[]).reduce((acc, key) => {
  acc[AccountType[key]] = key
  return acc
}, {} as Record<AccountType, string>)

For Clarity:

/*
 * reversed == {
 *   "goo": "Google",
 *   "boo": "Facebook",
 *   "wit": "Twitter",
 * }
 * reversed[AccountType.Google] === "Google" 👍
 */

Reference for TypeScript Record

To iterate:

for (const [key, value] of Object.entries(reversed)) {
  console.log(`${key}: ${value}`);
}

A nice helper function:

const getAccountTypeName = (type: AccountType) => {
  return reversed[type]
};

// getAccountTypeName(AccountType.Twitter) === 'Twitter'
Angelikaangelina answered 2/6, 2020 at 14:45 Comment(3)
How does it "reverse" enum Test8 { A = "A", B = "A" }? The question asked for a way to "get each enumerated symbol name", i.e. for a list of keys.Gulick
@Gulick you're right, I didn't spell out how to iterate with Object.entriesAngelikaangelina
I came here for the type: +1 for keyof typeof <ENUM>Plunder
G
6

Having numeric enum:

enum MyNumericEnum {
 First = 1,
 Second = 2
}

You need to convert it to array first:

const values = Object.values(MyNumericEnum);
// ['First', 'Second', 1, 2]

As you see, it contains both keys and values. Keys go first.

After that, you can retrieve its keys:

values.slice(0, values.length / 2);
// ['First', 'Second']

And values:

values.slice(values.length / 2);
// [1, 2]

For string enums, you can use Object.keys(MyStringEnum) in order to get keys and Object.values(MyStringEnum) in order to get values respectively.

Though it's somewhat challenging to extract keys and values of mixed enum.

Gipsy answered 22/2, 2022 at 23:48 Comment(3)
For numeric enum enum Test { A = 0, B = -1 } it produces ["A", 0] as keys.Gulick
Yes, having negative value seems to break the usual order. In this case slice operation won't work and some sort of filtering has to be applied (may include regexp).Gipsy
Having your example, it would be something like this: const enumValues = Object.values(Test); const keys = enumValues.filter((value) => !(/^-?\d+$/.test(value))); const values = enumValues.filter((value) => /^-?\d+$/.test(value));Gipsy
F
5

The only solution that works for me in all cases (even if values are strings) is the following :

var enumToString = function(enumType, enumValue) {
    for (var enumMember in enumType) {
        if (enumType[enumMember]==enumValue) return enumMember
    }
}
Fairly answered 18/1, 2018 at 15:44 Comment(1)
This searches for enum key by value. Question asked for "get each enumerated symbol name".Gulick
T
5

typescript playground example

enum TransactionStatus {
  SUBMITTED = 'submitted',
  APPROVED = 'approved',
  PAID = 'paid',
  CANCELLED = 'cancelled',
  DECLINED = 'declined',
  PROCESSING = 'processing',
}


let set1 = Object.entries(TransactionStatus).filter(([,value]) => value === TransactionStatus.SUBMITTED || value === TransactionStatus.CANCELLED).map(([key,]) => {
    return key
})


let set2 = Object.entries(TransactionStatus).filter(([,value]) => value === TransactionStatus.PAID || value === TransactionStatus.APPROVED).map(([key,]) => {
    return key
})

let allKeys = Object.keys(TransactionStatus)



console.log({set1,set2,allKeys})
Textbook answered 1/9, 2022 at 19:59 Comment(0)
M
4

You can use the enum-values package I wrote when I had the same problem:

Git: enum-values

var names = EnumValues.getNames(myEnum);
Muumuu answered 23/7, 2016 at 10:20 Comment(7)
You aren't really answering the question, it would be better to document your answer with code/etc but I did find the package useful.Corrinnecorrival
Looks like the magic line is Object.keys(e).filter(key => isNaN(+key)), which will not work with string enums, etc, right?Fumed
@Fumed it will work. You can look at this testMuumuu
No, you can't, because it's buggy: for enum Test { A = 0, B = NaN } it returns ["A", "B", "NaN"].Gulick
@Gulick Yes this is an edge case, but not an interesting one. Who will ever define an enum like this? It is like arguing to not use '+' for adding numbers because when you pass it a string it concatenates instead of adding. As I see enums are keys mapped to either a string or a number. If you map it to a NaN, you are doing something wrongMuumuu
Well, the only reason there is such an edge case is subpar programming practice. Current test is no better than if (someBool.toString() === 'true'): a random conversion that the problem never even needed.Gulick
@Gulick I don't see how an invalid input makes the code incorrect. Validation could be added, but I think for this case, it's not interesting because it never happens in real life programmingMuumuu
K
4

I found this question by searching "TypeScript iterate over enum keys". So I just want to post solution which works for me in my case. Maybe it'll help to someone too.

My case is the following: I want to iterate over each enum key, then filter some keys, then access some object which has keys as computed values from enum. So this is how I do it without having any TS error.

    enum MyEnum = { ONE = 'ONE', TWO = 'TWO' }
    const LABELS = {
       [MyEnum.ONE]: 'Label one',
       [MyEnum.TWO]: 'Label two'
    }


    // to declare type is important - otherwise TS complains on LABELS[type]
    // also, if replace Object.values with Object.keys - 
    // - TS blames wrong types here: "string[] is not assignable to MyEnum[]"
    const allKeys: Array<MyEnum> = Object.values(MyEnum)

    const allowedKeys = allKeys.filter(
      (type) => type !== MyEnum.ONE
    )

    const allowedLabels = allowedKeys.map((type) => ({
      label: LABELS[type]
    }))
Kalinda answered 17/4, 2019 at 16:21 Comment(0)
S
4

You can get an array of names from Enum in this way:

const enumNames: string[] = Object.keys(YourEnum).filter(key => isNaN(Number(key)));
Shakedown answered 25/4, 2021 at 9:41 Comment(1)
For enum Test { A = 0, B = NaN } it returns ["A", "B", "NaN"].Gulick
H
4

In case if you want to get the name in the html

For this enum

enum CanadianProvinces {
    AB,
    BC,
    MB,
    NB,
    NL,
    NT,
    NS,
    NU,
    ON,
    PE,
    QC,
    SK,
    YT
}

Assign a variable in your component as

canadianProvinces = CanadianProvinces 

Then, in your html

{{canadianProvinces[0]}}
Hoard answered 20/9, 2022 at 23:43 Comment(1)
wicked sorcery!Ashram
L
3

Old question, but, why do not use a const object map?

Instead of doing this:

enum Foo {
    BAR = 60,
    EVERYTHING_IS_TERRIBLE = 80
}

console.log(Object.keys(Foo))
// -> ["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE", 60, 80]

Do this (pay attention to the as const cast):

const Foo = {
    BAR: 60,
    EVERYTHING_IS_TERRIBLE: 80
} as const

console.log(Object.keys(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> [60, 80]
Lebna answered 28/10, 2019 at 18:52 Comment(4)
Correct me if im wrong but console.log(Object.keys(Foo)) in the first example only returns ["BAR", "EVERYTHING_IS_TERRIBLE"]..Hbeam
@Hbeam give a look here at the ts playground, just open the console and click on run. At least for me, it prints ["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]Lebna
it seems your right, the fun thing if you change from numbers to strings you get the output i expected, i have no idea why typescript handles string and numbers differently in enums..Hbeam
Because the question asks specifically for a way to iterate over enum?Gulick
B
3

If you have enum

enum Diet {
  KETO = "Ketogenic",
  ATKINS = "Atkins",
  PALEO = "Paleo",
  DGAF = "Whatever"
}

Then you can get key and values like:

Object.keys(Diet).forEach((d: Diet) => {
  console.log(d); // KETO
  console.log(Diet[d]) // Ketogenic
});
Birdlime answered 5/2, 2020 at 23:17 Comment(2)
This causes an error: Argument of type '(d: Diet) => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'. Types of parameters 'd' and 'value' are incompatible. Type 'string' is not assignable to type 'MyEnum'.(2345)Gupton
For enum Test2 { A, B } it shows "0", "1", "A", "B" as keys.Gulick
L
2

I find that solution more elegant:

for (let val in myEnum ) {

 if ( isNaN( parseInt( val )) )
     console.log( val );
}

It displays:

bar 
foo
Libre answered 7/9, 2016 at 14:53 Comment(1)
For enum Test { A = 0, B = NaN } produces ["A", "B", "NaN"].Gulick
W
2

To get the list of the enum values you have to use:

enum AnimalEnum {
  DOG = "dog", 
  CAT = "cat", 
  MOUSE = "mouse"
}

Object.values(AnimalEnum);
Wooton answered 4/6, 2020 at 19:21 Comment(3)
It's sadly not working as expected for enum with int valuesTerrence
What is the result in the case of int values?Wooton
It will return the name of the enum AND the int value. Example: ["DOG", "CAT", "MOUSE", 1, 2, 3] Terrence
G
2

I hope the question is still relevant. I use such functions:

function enumKeys(target: Record<string, number|string>): string[] {
  const allKeys: string[] = Object.keys(target);
  const parsedKeys: string[] = [];

  for (const key of allKeys) {
    const needToIgnore: boolean
      = target[target[key]]?.toString() === key && !isNaN(parseInt(key));

    if (!needToIgnore) {
      parsedKeys.push(key);
    }
  }

  return parsedKeys;
}

function enumValues(target: Record<string, number|string>): Array<string|number> {
  const keys: string[] = enumKeys(target);
  const values: Array<string|number> = [];

  for (const key of keys) {
    values.push(target[key]);
  }

  return values;
}

Example:

enum HttpStatus {
  OK,
  INTERNAL_ERROR,
  FORBIDDEN = 'FORBIDDEN',
  NOT_FOUND = 404,
  BAD_GATEWAY = 'bad-gateway'
}


console.log(enumKeys(HttpStatus));
// > ["OK", "INTERNAL_ERROR", "FORBIDDEN", "NOT_FOUND", "BAD_GATEWAY"] 

console.log(enumValues(HttpStatus));
// > [0, 1, "FORBIDDEN", 404, "bad-gateway"]
Gingili answered 22/12, 2020 at 11:51 Comment(4)
I'm using TS 3.7.1 and it gives TS errors for the parsedKeys and values vars. This can be fixed by typing out the values variable as Array<string | number> and the parsedKeys variable as string[].Missend
@YulricSequeira Thank you! Updated types for variables' initialization.Gingili
isNaN(parseInt(key) is otherwise called typeof key !== 'number'. Convering a number to string and then back to number just to check that it's really a number is not smart.Gulick
@Gulick Not quite so. isNaN(parseInt(key) gives more information, such as whether the string is a numeric string.Gingili
T
2

This would work more efficiently for key-value based enum:

enum yourEnum {
  ["First Key"] = "firstWordValue",
  ["Second Key"] = "secondWordValue"
}

Object.keys(yourEnum)[Object.values(yourEnum).findIndex(x => x === yourValue)]
// Result for passing values as yourValue
// FirstKey
// SecondKey
Toluca answered 15/4, 2021 at 19:25 Comment(1)
What is yourValue? Question is to "get each enumerated symbol name".Gulick
M
2

Can be short and simple:

enum AnimalEnum {
  DOG = "dog", 
  CAT = "cat", 
  MOUSE = "mouse"
}

Object.keys(AnimalEnum).filter(v => typeof v == 'string' && isNaN(v))
Mcardle answered 18/9, 2021 at 7:56 Comment(2)
For enum Test { A = 0, B = NaN } produces ["A", "B", "NaN"].Gulick
let filteredKeys = Object.entries(AnimalEnum).filter(([,value]) => value === AnimalEnum.DOG || value === AnimalEnum.CAT).map(([key,]) => { return key })Textbook
L
2

You can do the following, which I think is shortest, cleanest and fastest:

Object.entries(test).filter(([key]) => (!~~key && key !== "0"))

Given the following mixed type enum definition:

enum testEnum {
  Critical = "critical",
  Major = 3,
  Normal = "2",
  Minor = "minor",
  Info = "info",
  Debug = 0
};

It will get transpire to the following:

var testEnum = { 
  Critical: 'critical', 
  Major: 3,
  Normal: "2",
  Minor: 'minor',
  Info: "info",
  Debug: 0,
  [0]: "critical",
  [1]: 3,
  [2]: "2",
  [3]: "minor",
  [4]: "info",
  [5]: 0
}

function safeEnumEntries(test) {
    return Object.entries(test).filter(([key]) => (!~~key && key !== "0"));
};

console.log(safeEnumEntries(testEnum));

After executing the function, you will get only the good entries:

[
  ["Critical", "critical"],
  ["Major", 3],
  ["Normal", "2"],
  ["Minor", "minor"],
  ["Info", "info"],
  ["Debug", 0]
] 
Limoli answered 30/3, 2022 at 1:29 Comment(2)
For enum Test { A = 0, B = NaN } returns ["A", "B", "NaN"].Gulick
Also it's not "cleanest", it's "clever", which is regarded as antipattern.Gulick
C
1

My Enum is like this:

export enum UserSorting {
    SortByFullName = "Sort by FullName", 
    SortByLastname = "Sort by Lastame", 
    SortByEmail = "Sort by Email", 
    SortByRoleName = "Sort by Role", 
    SortByCreatedAt = "Sort by Creation date", 
    SortByCreatedBy = "Sort by Author", 
    SortByUpdatedAt = "Sort by Edit date", 
    SortByUpdatedBy = "Sort by Editor", 
}

so doing this return undefined:

UserSorting[UserSorting.SortByUpdatedAt]

To resolve this issue, I choose another way to do it using a Pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'enumKey'
})
export class EnumKeyPipe implements PipeTransform {

  transform(value, args: string[] = null): any {
    let enumValue = args[0];
    var keys = Object.keys(value);
    var values = Object.values(value);
    for (var i = 0; i < keys.length; i++) {
      if (values[i] == enumValue) {
        return keys[i];
      }
    }
    return null;
    }
}

And to use it:

return this.enumKeyPipe.transform(UserSorting, [UserSorting.SortByUpdatedAt]);
Chore answered 15/12, 2018 at 18:21 Comment(0)
A
0

It is not exactly answer of your question but it is a trick to tackle your problem.

export module Gender {

  export enum Type {
    Female = 1,
    Male = 2
  };

  export const List = Object.freeze([
    Type[Type.Female] ,
    Type[Type.Male]
  ]);

}

You can extend your list model in a way you want.

export const List = Object.freeze([
    { name: Type[Type.Female], value: Type.Female } ,
    { name: Type[Type.Male], value: Type.Male }
  ]);

Now, you can use it in this way:

for(const gender of Gender.List){
  console.log(gender.name);
  console.log(gender.value);
}

or:

if(i === Gender.Type.Male){
  console.log("I am a man.");
}
Aperient answered 12/1, 2019 at 22:49 Comment(0)
E
0

I wrote a helper function to enumerate an enum:

static getEnumValues<T extends number>(enumType: {}): T[] {
  const values: T[] = [];
  const keys = Object.keys(enumType);
  for (const key of keys.slice(0, keys.length / 2)) {
    values.push(<T>+key);
  }
  return values;
}

Usage:

for (const enumValue of getEnumValues<myEnum>(myEnum)) {
  // do the thing
}

The function returns something that can be easily enumerated, and also casts to the enum type.

Eure answered 21/11, 2019 at 3:6 Comment(1)
For enum Test1 { A = "C", B = "D" } returns [NaN].Gulick
G
0

Quite a few answers here and considering I looked it up despite this being 7 years old question, I surmise many more will come here. Here's my solution, which is a bit simpler than other ones, it handles numeric-only/text-only/mixed value enums, all the same.

enum funky {
    yum , tum='tum', gum = 'jump', plum = 4
}

const list1 = Object.keys(funky)
  .filter(k => (Number(k).toString() === Number.NaN.toString()));
console.log(JSON.stringify(list1)); // ["yum","tum","gum","plum"]" 

 // for the numeric enum vals (like yum = 0, plum = 4), typescript adds val = key implicitly (0 = yum, 4 = plum)
 // hence we need to filter out such numeric keys (0 or 4)
 
Gifford answered 1/12, 2020 at 18:49 Comment(1)
The thing you cherished the most betrayed you: for enum Test { A = 0, B = NaN } it returns ["A", "B", "NaN"].Gulick
J
0

My humble 2 cents based on reading an awesome comment from github TS discussion

const EnvironmentVariants = ['development', 'production', 'test'] as const 
type EPredefinedEnvironment = typeof EnvironmentVariants[number]

Then at compile time:

// TS2322: Type '"qaEnv"' is not assignable to type '"development" | "production" | "test"'.
const qaEnv: EPredefinedEnvironment = 'qa' 

at runtime:

function isPredefinedEnvironemt(env: string) {
  for (const predefined of EnvironmentVariants) {
    if (predefined === env) {
      return true
    }
  }
  return false
}

assert(isPredefinedEnvironemet('test'), true)
assert(isPredefinedEnvironemet('qa'), false)

Note, that for(const index in EnvironmentVariants) {...} will iterate over "0", "1", "2" set

Jari answered 1/7, 2022 at 17:11 Comment(0)
A
0

Here is a typed utility function which extracts enum names and values:

type Enum = { [key: string]: number | string };

function *enumNamesAndValues<E extends Enum>(e: E): Iterable<[keyof E, E[keyof E]]> {
    for (const key in e) {
        const value = e[key];
        if (typeof value === "number")
            yield [key, value];
    }
}

You can use it like this:

enum ETestEnum {
    Foo,
    Bar,
    Baz
}

const namesAndValues = [...enumNamesAndValues(ETestEnum)];

console.log(namesAndValues);

This prints:

[["Foo", 0], ["Bar", 1], ["Baz", 2]] 

Note that the type of namesAndValues is ["Foo" | "Bar" | "Baz", ETestEnum][].


Extracting only names or only values can be accomplished analogously:

function *enumNames<E extends Enum>(e: E): Iterable<keyof E> {
    for (const key in e) {
        const value = e[key];
        if (typeof value === "number")
            yield key;
    }
}

function *enumValues<E extends Enum>(e: E): Iterable<E[keyof E]> {
    for (const key in e) {
        const value = e[key];
        if (typeof value === "number")
            yield value;
    }
}
Aklog answered 5/3 at 8:53 Comment(0)
K
-1

Using a current version TypeScript you can use functions like these to map the Enum to a record of your choosing. Note that you cannot define string values with these functions as they look for keys with a value that is a number.

enum STATES {
  LOGIN,
  LOGOUT,
}

export const enumToRecordWithKeys = <E extends any>(enumeration: E): E => (
  Object.keys(enumeration)
    .filter(key => typeof enumeration[key] === 'number')
    .reduce((record, key) => ({...record, [key]: key }), {}) as E
);

export const enumToRecordWithValues = <E extends any>(enumeration: E): E => (
  Object.keys(enumeration)
    .filter(key => typeof enumeration[key] === 'number')
    .reduce((record, key) => ({...record, [key]: enumeration[key] }), {}) as E
);

const states = enumToRecordWithKeys(STATES)
const statesWithIndex = enumToRecordWithValues(STATES)

console.log(JSON.stringify({
  STATES,
  states,
  statesWithIndex,
}, null ,2));

// Console output:
{
  "STATES": {
    "0": "LOGIN",
    "1": "LOGOUT",
    "LOGIN": 0,
    "LOGOUT": 1
  },
  "states": {
    "LOGIN": "LOGIN",
    "LOGOUT": "LOGOUT"
  },
  "statesWithIndex": {
    "LOGIN": 0,
    "LOGOUT": 1
  }
}
Kopeck answered 26/2, 2020 at 17:48 Comment(2)
.reduce((accum, key) => ({...accum, [key]: ... }), {}) is an antipattern with O(N^2) complexity. Don't use this code.Gulick
For enum Test1 { A = "C", B = "D" } the result of enumToRecordWithKeys is {}.Gulick
F
-1

If it's your enum and you define as seen below, names and values are the same, it'll give you the entries' names directly.

enum myEnum { 
    entry1="entry1", 
    entry2="entry2"
 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}
Fencesitter answered 15/3, 2021 at 16:33 Comment(2)
No, they're not? Try enum Test3 { A = 0, B = "C" }.Gulick
@Gulick I think you missed my if condition . :)Davy

© 2022 - 2024 — McMap. All rights reserved.