Home > front end >  Typescript string enum inverse mapping
Typescript string enum inverse mapping

Time:04-09

I have a string enum defined as follows:

export enum UserRole {
  SHOP_DESIGNER = 'DG_PF00-CorpID-Designa_Shop-Designers',
  SHOP_EMPLOYEE = 'DG_PF00-CorpID-Designa_Shop-Employees',
  LOGISTICS_TEAM = 'DG_PF00-CorpID-Designa_Logistics',
}

I want to create a type-safe mapping from a an enum string value to its enum type:

const USER_ROLE_NAMES<string, UserRole> = ....

So I can parse an arbitrary value by querying the map:

let role: UserRole

// role = SHOP_DESIGNER 
role = USER_ROLE_NAMES.get('DG_PF00-CorpID-Designa_Shop-Designers')

// role = SHOP_DESIGNER 
role = USER_ROLE_NAMES.get('DG_PF00-CorpID-Designa_Shop-Employees')

// role = SHOP_DESIGNER 
role = USER_ROLE_NAMES.get('DG_PF00-CorpID-Designa_Logistics')

// role = undefined
role = USER_ROLE_NAMES.get('some arbitrary string value which is not an enum value')

I already tried the following:

export const USER_ROLE_NAMES = new Map(Object.entries(UserRole).map(([key, value]: [string, UserRole]) => [value, key]));

but then the type of USER_ROLE_NAMES is Map<UserRole, string> and the map cannot be queried with a string.

If I invert the mapping

export const USER_ROLE_NAMES = new Map(Object.entries(UserRole).map(([key, value]: [string, UserRole]) => [key, value]));

then the type is correct, but the mapping is wrong ('DESIGNA_USER' => 'DG_PF00-CorpID-Designa_Users',... instead of 'DG_PF00-CorpID-Designa_Users' => 'DESIGNA_USER',...

CodePudding user response:

At runtime, the value of UserRole.SHOP_DESIGNER is actually 'DG_PF00-CorpID-Designa_Shop-Designers', not 'SHOP_DESIGNER'. So the mapping you are asking for would look like this (at runtime):

const theMapping ={
  'DG_PF00-CorpID-Designa_Shop-Designers': 'DG_PF00-CorpID-Designa_Shop-Designers',
  ...
}

If you want this "enum value" -> "enum member" mapping, you can construct it like this: TypeScript playground link

export enum UserRole {
  SHOP_DESIGNER = 'DG_PF00-CorpID-Designa_Shop-Designers',
  SHOP_EMPLOYEE = 'DG_PF00-CorpID-Designa_Shop-Employees',
  LOGISTICS_TEAM = 'DG_PF00-CorpID-Designa_Logistics',
}

const mapping: Map<string, UserRole> = new Map(Object.values(UserRole).map(
    (memberValue) => [`${memberValue}`, memberValue] as const
))

let role1 = mapping.get('DG_PF00-CorpID-Designa_Shop-Designers')
let role2 = mapping.get('unknown')
  • Related