Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map Typescript Enum

How would I map a typescript enum? For example, with strings you can do this:

let arr = [ 'Hello', 'Goodbye' ];  arr.map(v => {   if (v === 'Hello') {     return ':)';   } else if (v === 'Goodbye') {     return ':(';   } ); // [ ':)', ':(' ] 

This, of course, doesn't work with enums:

enum MyEnum { Hello, Goodbye };  MyEnum.map(v => {   if (v === MyEnum.Hello) {     return ':)';   } else if (v === MyEnum.Goodbye) {     return ':(';   } }); // does not work 

Ideally, I'd like to do this in a generalized way so I can simply take any enum I have and put it through a map function while preserving type information. Usage might look something like this:

map(MyEnum, v => {   if (v === MyEnum.Hello) {     return ':)';   } else if (v === MyEnum.Goodbye) {     return ':(';   } }); // [ ':)', ':(' ] 

I've been fiddling around with getting a function that does this for me but keep having issues getting the generics just right.

like image 412
Braden Snell Avatar asked Dec 23 '16 21:12

Braden Snell


People also ask

Can you map an enum TypeScript?

Use the map() method with Enums in TypeScript # To use the map() method with enums: Use the Object. keys() method to get an array of the enum's keys.

What is the use of enum in TypeScript?

Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript. Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.

Should I use enum in TypeScript?

Enums in TypeScript are a very useful addition to the JavaScript language when used properly. They can help make it clear the intent of normally “magic values” (strings or numbers) that may exist in an application and give a type-safe view of them.


2 Answers

To map an enum do this:

(Object.keys(MyEnum) as Array<keyof typeof MyEnum>).map((key) => {}) 
like image 124
Justidude Avatar answered Sep 23 '22 08:09

Justidude


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.

like image 37
James Monger Avatar answered Sep 22 '22 08:09

James Monger