Question
In TypeScript, what is the correct way to loop through the members of an enum?
I am using this enum:
export enum MotifIntervention {
Intrusion,
Identification,
AbsenceTest,
Autre
}
And in my class I am doing this:
export class InterventionDetails implements OnInit {
constructor(private interService: InterventionService) {
for (let motif in MotifIntervention) {
console.log(motif);
}
}
}
The output is:
0
1
2
3
Intrusion
Identification
AbsenceTest
Autre
I want the loop to run only once for each enum member, because the enum has only four elements. I do not want the 0, 1, 2, and 3 entries, which appear to be numeric indexes from the enum.
Short Answer
By the end of this page, you will understand why looping over a numeric enum in TypeScript shows both numbers and names, how enum reverse mapping works, and how to get only the values you want for tasks like rendering radio buttons.
Concept
TypeScript enums are compiled into JavaScript objects. For numeric enums, TypeScript creates a two-way mapping:
- from name to number
- from number back to name
For example, this enum:
enum MotifIntervention {
Intrusion,
Identification,
AbsenceTest,
Autre
}
becomes conceptually similar to:
{
0: "Intrusion",
1: "Identification",
2: "AbsenceTest",
3: "Autre",
Intrusion: 0,
Identification: 1,
AbsenceTest: 2,
Autre: 3
}
That is why a for...in loop prints both numeric keys and string keys.
This matters because enums are often used for:
- form options
- dropdowns
- radio buttons
- status values
- API-related constants
If you do not understand the reverse mapping behavior, you may accidentally render duplicate options or process the wrong values.
Mental Model
Think of a numeric enum like a bilingual dictionary:
- one side says
Intrusion -> 0 - the other side says
0 -> Intrusion
When you loop through the whole object, you are opening both sides of the dictionary, so you see entries in both directions.
If you only want labels for radio buttons, you should read just one side of the dictionary instead of both.
Syntax and Examples
The most common way to loop through only the names of a numeric enum is to filter out numeric keys.
enum MotifIntervention {
Intrusion,
Identification,
AbsenceTest,
Autre
}
const names = Object.keys(MotifIntervention).filter(key => isNaN(Number(key)));
console.log(names);
// ["Intrusion", "Identification", "AbsenceTest", "Autre"]
Why this works
Object.keys(...)returns all keys from the enum object- numeric enums contain keys like
"0","1", as well as"Intrusion" filter(key => isNaN(Number(key)))keeps only the non-numeric keys
Example for radio buttons
enum MotifIntervention {
Intrusion,
,
,
}
motifOptions = .()
.( ((key)));
( option motifOptions) {
.(option);
}
Step by Step Execution
Consider this code:
enum MotifIntervention {
Intrusion,
Identification,
AbsenceTest,
Autre
}
const allKeys = Object.keys(MotifIntervention);
console.log(allKeys);
const namesOnly = allKeys.filter(key => isNaN(Number(key)));
console.log(namesOnly);
Step 1: The enum is created
TypeScript builds an object that contains:
{
0: "Intrusion",
1: "Identification",
2: "AbsenceTest",
3: "Autre",
Intrusion: 0,
Identification: 1,
AbsenceTest: 2,
Autre: 3
}
Step 2: reads all keys
Real World Use Cases
Enums are often looped over when you need to build UI or enforce a controlled set of values.
Common use cases
- Radio buttons for predefined choices such as status or category
- Dropdown menus for user-selectable options
- Validation rules where input must match one of several allowed values
- API payloads where only known values are accepted
- Configuration settings such as themes, roles, or modes
Example: rendering radio button options
const motifOptions = Object.keys(MotifIntervention)
.filter(key => isNaN(Number(key)));
You can then bind motifOptions in your component template.
Example: validating input
function isValidMotif(value: string): boolean {
return Object.keys(MotifIntervention)
.filter(key => ((key)))
.(value);
}
Real Codebase Usage
In real projects, developers usually do not loop over enums directly inside random parts of the code every time. Instead, they create a reusable list of options.
Common pattern: build UI options once
enum MotifIntervention {
Intrusion,
Identification,
AbsenceTest,
Autre
}
const motifOptions = Object.keys(MotifIntervention)
.filter(key => isNaN(Number(key)))
.map(key => ({
label: key,
value: MotifIntervention[key as keyof typeof MotifIntervention]
}));
This produces objects like:
[
{ label: "Intrusion", value: 0 },
{ label: "Identification", value: 1 },
{ label: "AbsenceTest", value: },
{ : , : }
]
Common Mistakes
1. Using for...in without understanding enum reverse mapping
Broken example:
for (const key in MotifIntervention) {
console.log(key);
}
This prints both numeric and string keys for numeric enums.
Fix: filter the keys.
for (const key of Object.keys(MotifIntervention).filter(k => isNaN(Number(k)))) {
console.log(key);
}
2. Assuming enums behave like arrays
Broken example:
console.log(MotifIntervention.length);
Enums are objects, not arrays. They do not have an array length.
use and filter if needed.
Comparisons
| Approach | What it gives you | Good for | Notes |
|---|---|---|---|
for...in on numeric enum | Numeric and string keys | Rarely useful directly | Causes duplicate-looking output |
Object.keys(enum).filter(...) | Enum member names only | Display labels, radio buttons | Common solution for numeric enums |
Object.values(enum).filter(...) | Values only | Getting numeric enum values | Simpler in newer JS environments |
String enum + Object.keys(...) | Clean names only | UI-friendly enums | No reverse mapping |
| Plain array of objects | Full control over labels and values |
Cheat Sheet
Numeric enum
enum MotifIntervention {
Intrusion,
Identification,
AbsenceTest,
Autre
}
Get only enum names
const names = Object.keys(MotifIntervention)
.filter(key => isNaN(Number(key)));
Get only numeric values
const values = Object.values(MotifIntervention)
.filter(value => typeof value === "number");
Build radio button options
const options = Object.keys(MotifIntervention)
.filter(key => ((key)))
.( ({
: key,
: [key keyof ]
}));
FAQ
Why does TypeScript enum iteration show both names and numbers?
Because numeric enums are compiled into objects with reverse mappings. They store both name -> value and value -> name.
How do I loop through only enum names in TypeScript?
Use:
Object.keys(MyEnum).filter(key => isNaN(Number(key)))
How do I loop through only enum values?
For numeric enums, use:
Object.values(MyEnum).filter(value => typeof value === "number")
Are string enums easier to use for display?
Yes. String enums do not create reverse mappings, so they are often simpler for UI display.
Should I use enums for radio button labels?
You can, but in many real applications a plain array of { label, value } objects is even clearer, especially when labels need formatting.
Is for...in wrong for enums?
Mini Project
Description
Create a small TypeScript utility that turns an enum into a list of radio button options. This demonstrates how to safely loop through enum members and prepare data for UI rendering without including unwanted numeric reverse-mapping keys.
Goal
Build a reusable function that converts a numeric enum into a clean array of { label, value } option objects.
Requirements
- Create a numeric enum with at least four members.
- Write a function that extracts only the enum names.
- Convert those names into
{ label, value }objects. - Print the resulting options array.
- Make sure no numeric keys appear in the final output.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.
Angular @ViewChild Returning Undefined: Lifecycle, Child Components, and Fixes
Learn why Angular @ViewChild can be undefined, when it becomes available, and how to access child components correctly using lifecycle hooks.