18

I would like a simple way to get a list of keys from an enumerator, I tried Object.keys, but it returned 6 keys, 0-5, I think it occours because when I tried foreach the enum, this returned keys and values list, is there a simple way to return only keys, I would not like to return to mount and return another list.

I will use this with react

My enum:

enum ObservationType {
    Accomodation = 1,
    Addtional = 2,
    LandTransport = 3
}

Sample that I tried and returned six values:

{Object.keys(ObservationType).map((type) => <div>{type}</div>)}
3
  • I got a solution, but I wonder if I can do it better. My solution: Object.keys(ObservationType).filter(o => !isNaN(o as any)) Commented Jan 24, 2018 at 2:00
  • Why are you trying to get these keys? Commented Jan 24, 2018 at 2:15
  • I need to show some fields for each observation type with some particularities Commented Jan 24, 2018 at 3:42

8 Answers 8

12

Try using

Object.keys(enumObj).filter(key => isNaN(Number(key)))

It covers all types of enums including Heterogeneous enums.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a little hacky but probably the easiest and shortest way to do this for now. I do it the same way.
5

From the TypeScript enum documentation:

In this generated code, an enum is compiled into an object that stores both forward (name -> value) and reverse (value -> name) mappings. References to other enum members are always emitted as property accesses and never inlined.

Keep in mind that string enum members do not get a reverse mapping generated at all.

This means that if you're able, you may want to use string enums, e.g.:

enum ObservationType {
  Accomodation = 'Acc',
  Addtional = 'Addt',
  LandTransport = 'LandT',
}

// Object.keys will only have the three keys.

Another way to handle this would be to keep track of the mapped values to get the reverse mappings only once. This requires the numeric keys of the object to be set first which is not necessarily a guarantee:

enum ObservationTypeNums {
  Accomodation,
  Addtional,
  LandTransport,
}

Object.keys(ObservationTypeNums).reduce((arr, key) => {
  if (!arr.includes(key)) {
    arr.push(ObservationTypeNums[key]);
  }
  return arr;
}, []);

// arr now has only the string keys

Otherwise you will just have to filter out numeric keys in a way as you have done.

2 Comments

This can easily be done by const keys = Object.keys(ObservationTypeNums); const enumValues = keys.slice(keys.length / 2); // only string keys
Why does Angular have such an issue with numeric enums?! It should be able to just display the string keys of an enum on a dropdown box and use the corresponding numeric value to set as currently selected item but nooooooo that would be far too simple for Angular...
5

Try using ts-enum-util (github, npm):

import {$enum} from "ts-enum-util";

enum ObservationType {
    Accomodation = 1,
    Addtional = 2,
    LandTransport = 3
}

// type: ObservationType[]
// value: [1, 2, 3]
const values = $enum(ObservationType).getValues();

// type: ("Accomodation" | "Addtional" | "LandTransport")[]
// value: ["Accomodation", "Addtional", "LandTransport"]
const keys = $enum(ObservationType).getKeys();

// directly map the enum value/key pairs
const valueDivs = $enum(ObservationType).map(
    (value, key) => <div>{value}</div>
)

It takes care of ignoring the numeric key reverse lookup entries in the runt-time enum object for you, among other things.

Comments

2

How about, Object.keys(ObservationType).filter(k => isNaN(Number(k)))

credit to @basarat whose answer I built on.

Comments

2

I had a hard time finding a good answer to this.

It looks like the enum generates an Object like this:

{
  key0: 0,
  key1: 1,
  0: key0,
  1: key1
}

So this is what I did:

const observationTypes: string[] = Object.keys(ObservationType).filter((_, i) => ObservationType[i] !== undefined).map((_, i) => ObservationType[i]);

This gives me an array of strings:

{
  0: "a",
  1: "b",
  2: "c",
  3: "d",
  4: "e",
  ...
}

You could easily modify this to create a set of elements like in your question.

Comments

2

For string enums (with string values) you can just use Object.keys(myEnum) / Object.values(myEnum)

For numeric enums, the following methods works without isNan, which can go wrong for certain keys:

/**
 * Get the values for an enum that is numeric (has number values).
 */
export function enumValues(myEnum) {
    return Object.values(myEnum).filter((o) => typeof o == 'number');
}

/**
 * Get the keys for an enum that is numeric (has number values).
 */
export function enumKeys(myEnum) {
    return Object.values(myEnum).filter((o) => typeof o == 'string');
}

Comments

2

The following can map the keys of the enum and you can use ObservationType[key] to get the value for each one as you go.

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

Comments

2

The ObservationType object will have keys :Accomodation, Additional, LandTransport, 1, 2, 3 and is fundamental to how enums work in TypeScript.

That said if you want just the string names you can with a simple filter:

{Object.keys(ObservationType)
  .filter(k => typeof key === 'string')
  .map((type) => <div>{type}</div>)}

5 Comments

Thanks basarat, it's like my solution that I posted as a comment to my post, my target was get only number values, so I did it: Object.keys(ObservationType).filter(o => !isNaN(o as any))
isNaN to check number is a bad idea. It should be used for NaN (not a number is a special value)
This won't work. Object.keys(['a', 'b', 'c']).filter(key => typeof key === 'string') will yield ['0', '1', '2']. All object keys are strings or symbols in JavaScript. Also, there's a typo in your code (k vs. key).
@philraj is correct, the check should be done with Number.isInteger, because the runtime type of all the keys of an object is always string.
@fortran actually if you have an enum of number types, which is very common use of javascript enums, this usage of Number.isInteger or even using the !isNan(Number.isInteger(enumKey)) won't work. I couldn't find a way of fltering those keys for an enum of any type, but I think you can have different functions to filter from a enum of string type and another for enum of number type, then you could filter from the opposite type that you don't want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.