Home > OS >  Infer key of object according to enum property in Typescript
Infer key of object according to enum property in Typescript

Time:02-02

enum Group {
   Group1 = "group1", 
   Group2 = "group2"
}

const map = {
   [SomeEnum.Group1]: "some val" // key is typed as "group1"
}

switch (group){
   case Group.Group1: {
      const val = map[group] // group is typed as Group.Group1 
   }
}

Typescript infers type of key in map to enum property value, while it infers type of group in the case clause according to the enum property itself. Therefor it can't infer type of val. How can I make the key in map to be inferred according to the enum, not the value?

CodePudding user response:

If I understood the question correctly, this will give you the value:

enum Group {
  Group1 = "group1",
  Group2 = "group2",
}

interface MyInterface {
  key1: Group
  key2: Group
}

const map: MyInterface = {
  key1: Group.Group1,
  key2: Group.Group2,
}

function getValue(group: Group): Group {
  switch (group) {
    case Group.Group1: {
      return map.key1
    }
    case Group.Group2: {
      return map.key2
    }
  }
}


let value1 = getValue(map.key1)
let value2 = getValue(map.key2)

console.log(value1) // will log: "group1"
console.log(value2) // will log: "group2"

The key point is to define an interface so that you can have a strongly typed property in your map object.

CodePudding user response:

const val = map[group] // group is typed as Group.Group1

This is the awaited infer, since you actually are in the Group.Group1 case. add a Group.Group2 case, and group would be inferred as Group.Group2 in it.

It would be the same inside a if block.

I am not sure what you are looking for but i have the feeling you need to strongly type your map const :

const map : Partial<{[key in Group]:string}> = { [Group.Group1]: "some val" }

(supposed same as @Ben Carp)

OPTION 2 :

remove the enum (if possible),

const GroupNames = ['Group1','Group2'] as const
type Group = typeof GroupNames[number];

const map : Partial<{[key in Group]:string}> = { Group1:"seomthing" }

const group : Group = "Group1"

switch (group){
   case 'Group1': {
      const val = map[group] // group is typed as 'Group1'
   }
}

The drawback is that you lost the value of Group.Group1 (ie 'group1' string).

  • Related