Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I map from a Typescript Enum to objects I generate based off Enum keys and properties?

I have a typescript enum:

export enum LanguagesEnglish  {
  'enUS'= 'English',
  'zhHant'= 'Mandarin, Traditional',
};

I would like to use it to generate options for a selector component. To do so, I think I should be able to map over the keys of the enum to generate objects in the shape the selector component library requires, defined as:

type pickerOption = {
  code: string,
  label: string,
};

I try to define that type as

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

type pickerOption = {
  code: keyof LanguagesEnglish,
  label: LanguagesEnglish,
};

Now, I’d like to generate objects of this type and put them in an array.

function generateOption(key: keyof LanguagesEnglish): pickerOption {
  return {
      code: key,
      label: LanguagesEnglish[key],
  }
}

Now to map over the enum and generate this array.

const options = Object.keys(LanguagesEnglish).map(generateOption);

I’ve been plagued with typescript errors that I find quite confusing. For example, in my generateOption function, the label property has an error.

  Element implicitly has an 'any' type because expression of type 'number | unique symbol | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | ... 35 more ... | "at"' can't be used to index type 'typeof LanguagesEnglish'.
   No index signature with a parameter of type 'number' was found on type 'typeof LanguagesEnglish'. (lsp)

This doesn’t make sense to me, because I explicitly indicated that key is not a number | unique symbol | ..., I indicated that it’s a keyof LanguagesEnglish in my function definition.

What’s the correct Typescript way to manage mapping back and forth between Enum types?

>Solution :

Enums are not what you expect them to be. In fact, in runtime, the enums are compilers to an object with the key: value and also value: key. Due to this and to other points, keyof SomeEnum is not what you want:

// number | typeof Symbol.iterator | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | ... 36 more ... | "valueOf"
type Case1 = keyof LanguagesEnglish;

What you should actually do is to get the keys of the type of the enum:

// type Case2 = "enUS" | "zhHant"
type Case2 = keyof typeof LanguagesEnglish;

Now, let’s update your types:

type pickerOption = {
  code: keyof typeof LanguagesEnglish;
  label: LanguagesEnglish;
};
function generateOption(key: keyof typeof LanguagesEnglish): pickerOption {
  return {
    code: key,
    label: LanguagesEnglish[key],
  };
}

Another issue is that Object.keys() don’t return the exact keys, but string[], which is described in this question.

So, unfortunately, we will need to use assertion to make the compiler happy:

const options = (
  Object.keys(LanguagesEnglish) as (keyof typeof LanguagesEnglish)[]
).map(generateOption);

playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading