Map Typescript Enum Map Typescript Enum javascript javascript

Map Typescript Enum


The function to solve this is quite simple.

// you can't use "enum" as a type, so use this.type EnumType = { [s: number]: string };function mapEnum (enumerable: EnumType, fn: Function): any[] {    // get all the members of the enum    let enumMembers: any[] = Object.keys(enumerable).map(key => enumerable[key]);    // we are only interested in the numeric identifiers as these represent the values    let enumValues: number[] = enumMembers.filter(v => typeof v === "number");    // now map through the enum values    return enumValues.map(m => fn(m));}

As you can see, we first need to get all of the keys for the enum (MyEnum.Hello is actually 1 at runtime) and then just map through those, passing the function on.

Using it is also simple (identical to your example, although I changed the name):

enum MyEnum { Hello, Goodbye };let results = mapEnum(MyEnum, v => {  if (v === MyEnum.Hello) {    return ':)';  } else if (v === MyEnum.Goodbye) {    return ':(';  }});console.log(results); // [ ':)', ':(' ]

The reason we need to filter the enum to be numbers only is because of the way enums are compiled.

Your enum is actually compiled to this:

var MyEnum;(function (MyEnum) {    MyEnum[MyEnum["Hello"] = 0] = "Hello";    MyEnum[MyEnum["Goodbye"] = 1] = "Goodbye";})(MyEnum || (MyEnum = {}));;

However we are not interested in "Hello" or "Goodbye" as we can't use those at runtime.


You will also notice a funny type statement right before the function. This is because you can't type a parameter as someParameter: enum, you need to explicitly state it as a number -> string map.


To map an enum do this:

(Object.keys(MyEnum) as Array<keyof typeof MyEnum>).map((key) => {})


With ts-enum-util (npm, github), it's easy, type-safe (uses generics), and takes care of skipping the numeric reverse lookup entries for you:

import { $enum } from "ts-enum-util";enum MyEnum { Hello, Goodbye };$enum(MyEnum).map(v => {    if (v === MyEnum.Hello) {        return ':)';    } else if (v === MyEnum.Goodbye) {        return ':(';    }}); // produces [':(', ':)']

NOTE: ts-enum-util always iterates based on the order of the sorted enum keys to guarantee consistent order in all environments. Object.keys() does not have a guaranteed order, so it's impossible to iterate enums "in the order they were defined" in a cross-platform guaranteed way.(update: new version of ts-enum-util now preserves the original order in which the enum was defined)

If you are using string enums, then combine it with ts-string-visitor (npm, github) for even more generic type-safe compiler checks to guarantee that you handle all possible enum values in your map function:(update: new version of ts-enum-util now includes functionality of ts-string-visitor, and it works on numeric enums now too!)

import { $enum } from "ts-enum-util";import { mapString } from "ts-string-visitor";enum MyEnum { Hello = "HELLO", Goodbye = "GOODBYE" };$enum(MyEnum).map(v => {    // compiler error if you forget to handle a value, or if you    // refactor the enum to have different values, etc.    return mapString(v).with({        [MyEnum.Hello]: ':)',        [MyEnum.Goodby]: ':('    });}); // produces [':(', ':)']