Here’s an overview of all the ways I’ve found to iterate an enum in TypeScript. I was particularly looking for how to iterate over the value of an enum, but still have the strongly typed value, instead of the underlying (string) value. But I decided to make this post about all possible ways I know of.
Default
Take this enum:
enum Color {
Red, Green
}
Now add this code to log the values:
for (const value in Color) {
log(value);
}
function log(value: string) {
console.log(`Value: ${value}`);
}
Note: I’m using a separate log function to show what type the value is. You’ll see why later
When we run this code, we see:
Value: 0
Value: 1
Value: Red
Value: Green
So that’s a special thing to note! The enum actually contains both the numerical and the string value. You can see this in the resulting Javascript code in the TypeScript Playground.
Number Values
If we only want the numbers, we can use this code to log:
function log(value: string) {
if (isNaN(Number(value))) {
return;
}
console.log(`Value: ${value}`);
}
Member Names
What if we want only the member names? Easy, we can specify the underlying values when we define our enum:
enum Color {
Red = "RED",
Green = "GREEN"
}
Using the same loop and console code, we now get this:
Value: Red
Value: Green
You could also leave the enum as it was (keeping both the underlying number and string values), and check the type when logging:
function log(value: string) {
if (!isNaN(Number(value))) {
return;
}
console.log(`Value: ${value}`);
}
String Values
You can loop over an enum and get the member names as well:
enum Color {
Red,
Green
}
for (const value in Object.keys(Color)) {
if (typeof Color[value] !== "string") {
continue;
}
log(Color[Number(value)]);
}
function log(value: string) {
console.log(`Value: ${value}`);
}
If the enum is backed by string values, this won’t work because the “value” in our loop is a string instead of a number. You might want to use this code:
enum Color {
Red = "RED",
Green = "GREEN"
}
function log(value: string) {
console.log(`Value: ${value}`);
}
for (const value in Color) {
log(Color[value]); // <----- Error
}
But this won’t work because “value” is a string to TypeScript, but the indexer of “Color” can only accept “Red” or “Green”. So we need a helper method to create a new type:
function enumKeys<O extends object, K extends keyof O = keyof O>(obj: O): K[] {
return Object.keys(obj).filter(k => Number.isNaN(+k)) as K[];
}
We can now use this code:
function log(value: Color) {
console.log(`Value: ${value}`);
}
for (const value of enumKeys(Color)) {
log(Color[value]);
}
This gives us the following result:
Value: RED
Value: GREEN
Also, notice how our “log” function now can accept a strongly-typed “Color” instead of a “string.”
Conclusion
So that’s basically it. There is code to get all the underlying values, the member names, the string values, and the strongly-typed values.
Thanks a lot for that!
I understand that they want to minimize the runtime impact of TypeScript but the lack of this function in TS has always been a pain point for me. I wrote that same function a few times, but not as concisely as you!
The helper enumKeys saved my life! Thanks Peter
const values = Object.values(Color);
values.forEach((value) => {
console.log("Value: " + value);
});
Prints:
Value: RED
Value: GREEN
I guess that’s basically a variant of my first version (under “Default”)? But when I test it, it also prints the numerical values.