I would like to iterate a TypeScript an enum
type and get each enumerated symbol name, e.g.:
enum myEnum { entry1, entry2 }
for (var entry in myEnum) {
// use entry's name here, e.g., "entry1"
}
Though the answer is already provided, Almost no one pointed to the docs
Here's a snippet
enum Enum {
A
}
let nameOfA = Enum[Enum.A]; // "A"
Keep in mind that string enum members do not get a reverse mapping generated at all.
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 = parseInt(enumMember, 10) >= 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.
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.
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']
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" ];
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
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]
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();
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
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)
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;
};
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'
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
I got tired looking through incorrect answers, and did it myself.
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"]
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]
}))
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"]
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]
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]);
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.
There are already a lot of answers here but I figure I'll throw my solution onto the stack anyway.
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
A nice helper function:
const getAccountTypeName = (type: AccountType) => {
return reversed[type]
};
// getAccountTypeName(AccountType.Twitter) === 'Twitter'
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"]
getAllEnumValues
andgetAllEnumKeys
for your purpose – transangfor (const [name, value] of MyEnum) {
to Typescript. Hopefully this will be easier one day! – Timmmm