Use Enum as restricted key type in Typescript

Typescript

Typescript Problem Overview


The question is can enum be used as a key type instead of only "number" or "string" ? Currently it seems like the only possible declaration is x:{[key:number]:any} where key can be of type "number" or "string". Is it possible to make something like in this example:

Example:

enum MyEnum
{
    First,
    Second
}

var layer:{[key:MyEnum]:any};

Typescript Solutions


Solution 1 - Typescript

Since 2018, there is an easier way in Typescript, without using keyof typeof:

let layer: { [key in MyEnum]: any}

To not have to include all keys:

let layer: { [key in MyEnum]?: any}

Solution 2 - Typescript

Yes. Just type

let layer:{[key in keyof typeof MyEnum]: any}

The keyof keyword is available since Typescript 2.1. See the TypeScript documentation for more details. Using only keyof for enums wouldn't work (you'd get the keys of the enum type and not the enum constants), so you have to type keyof typeof.

Solution 3 - Typescript

Short Answer:

let layer: Partial<Record<MyEnum, unknown>>;

Long Answer (with details):

I had the same problem. I wanted to have the following piece of code work.

enum MyEnum {
    xxx = "xxx",
    yyy = "yyy",
    zzz = "zzz",
}

type myType = ...; // Fill here

const o: myType = { // keys should be in MyEnum, values: number
   [MyEnum.xxx]: 2,
   "hi": 5, // <--- Error: complain on this one, as "hi" is not in enum
}

o[MyEnum.yyy] = 8; // Allow it to be modified later

Starting from the other answer on this question, I got to:

type myType = {[key in keyof typeof MyEnum]: number};

But it would nag that o is missing "yyy". So I needed to tell it that the object is going to have some of the enum keys, not all of them. So I got to add ? to get:

type myType = {[key in keyof typeof MyEnum]?: number};

It was working fine, until I added the line at the end of the code to modify the object after its first creation. Now it was complaining that the type inherited through keyof has its properties as readonly and I cannot touch them after the first creation! :| In fact, hovering over myType in Typescript Playground, it will be shown as:

type myType = {
    readonly xxx?: number | undefined;
    readonly yyy?: number | undefined;
    readonly zzz?: number | undefined;
}

Now, to remove that unwanted readonly, I found that I can use:

type myType = {-readonly [key in keyof typeof myEnum1]?: number };

Quite ugly, but working!

Until I played with Typescript Utility Types, and found what I wanted!

type myType = Partial<Record<keyof typeof MyEnum, number>>;

:)

Solution 4 - Typescript

For those who are seeking for a way to get the keys of the enum instead its value, you just need to change from this:

type myType = Partial<Record<MyEnum, number>>;

to that:

type myType = Partial<Record<keyof typeof MyEnum, number>>;

Solution 5 - Typescript

actually it worked with me without any workaround.

here is some cases:

enum EnumString {
  a="a",
  b="b"
}

enum EnumNum {
  a,
  b
}

type Type = "a" | "b"


let x1:{[k in EnumString]?:any }={a:1} //working
let x2:{[k in EnumNum]?:any }={a:1} //error: Type '{ a: number; }' is not assignable to type '{ 0?: any; 1?: any; }'
let x3:{[k in Type]?:any }={a:1} //working; defining a union type is easer than defining an enum string 

let y1:{[k: EnumString]?:any }={a:1}
let y2:{[k: EnumNum]?:any }={a:1}
let y3:{[k in Type]?:any }={a:1}

let z1:{[k in keyof typeof EnumString]?:any }={a:1}
let z2:{[k in keyof typeof EnumNum]?:any }={a:1}
let z3:{[k: keyof typeof Type]?:any }={a:1}

it is important to note that the case "z1", even it works well, but you cannot modify it later as it is a read only. you can use the keyword -readonly to remove this constraint.

x1.a=2 
x3.a=2
z1.a=2 //error: read only

I created a typescript playground to see issues of different cases yourself

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHivagaView Question on Stackoverflow
Solution 1 - TypescriptHugo Elhaj-LahsenView Answer on Stackoverflow
Solution 2 - TypescriptSebastianView Answer on Stackoverflow
Solution 3 - TypescriptAidinView Answer on Stackoverflow
Solution 4 - TypescriptAlecellView Answer on Stackoverflow
Solution 5 - TypescriptSh eldeebView Answer on Stackoverflow