patterntypescriptCritical
Use enum as restricted key type
Viewed 0 times
enumuserestrictedkeytype
Problem
Can an
enum be used as a key type instead of only number or string? Currently it seems like the only possible declaration is { [key: number]: any }, where key can be of type number or string. Is it possible to make something like in this example:enum MyEnum
{
First,
Second
}
var layer: { [key: MyEnum]: any };Solution
Since 2018, there is an easier way in Typescript, without using
To not have to include all keys:
To know the difference between
Other differences
With
... unless you use
But you can use any integer key?!:
Note both the
But with
It's a numeric enum. But we can't use any number:
The declaration compiles to:
We allow only
This is in line with how you would expect an enum to work, there are no surprises unlike
It works with string and heterogenous enums:
Here the type is:
Get immutability with
... which makes these keys
Summary
Compiles to enum values
Compiles to enum keys
Does not allow values outside the enum
Can allow numeric values outside the enum if you use a numeric enum
Can change the object, immutability opt-in with
Can't change enum props without
Use
keyof typeof:let obj: { [key in MyEnum]: any} =
{ [MyEnum.First]: 1, [MyEnum.Second]: 2 };To not have to include all keys:
let obj: { [key in MyEnum]?: any} =
{ [MyEnum.First]: 1 };To know the difference between
in and keyof typeof, continue reading.in Enum vs keyof typeof Enumin Enum compiles to enum values and keyof typeof to enum keys.Other differences
With
keyof typeof, you cannot change the enum properties:let obj: { [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj.First = 1;
// Cannot assign to 'First' because it is a read-only property.... unless you use
-readonly:let obj: { -readonly [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj.First = 1; // worksBut you can use any integer key?!:
let obj: { [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj[2] = 1;keyof typeof will compile to:{
[x: number]: any;
readonly First?: any;
readonly Second?: any;
}Note both the
[x: number] and the readonly properties. This [x: number] property doesn't exist with a string enum.But with
in Enum, you can change the object:enum MyEnum {
First, // default value of this is 0
Second, // default value of this is 1
}
let obj: { [key in MyEnum]?: any} = { [MyEnum.First]: 1 };
obj[MyEnum.First] = 1; // can use the enum...
obj[0] = 1; // but can also use the enum value,
// as it is a numeric enum by defaultIt's a numeric enum. But we can't use any number:
obj[42] = 1;
// Element implicitly has an 'any' type because
// expression of type '42' can't be used to index type '{ 0?: any; 1?: any; }'.
// Property '42' does not exist on type '{ 0?: any; 1?: any; }'.The declaration compiles to:
{
0?: any;
1?: any;
}We allow only
0 and 1, the values of the enum.This is in line with how you would expect an enum to work, there are no surprises unlike
keyof typeof.It works with string and heterogenous enums:
enum MyEnum
{
First = 1,
Second = "YES"
}
let obj: { [key in MyEnum]?: any} = { [MyEnum.First]: 1, [MyEnum.Second]: 2 };
obj[1] = 0;
obj["YES"] = 0;Here the type is:
{
1?: any;
YES?: any;
}Get immutability with
readonly:let obj: { readonly [key in MyEnum]?: any} = {
[MyEnum.First]: 1,
};
obj[MyEnum.First] = 2;
// Cannot assign to '1' because it is a read-only property.... which makes these keys
readonly:{
readonly 1?: any;
readonly 2?: any;
}Summary
in Enumkeyof typeof EnumCompiles to enum values
Compiles to enum keys
Does not allow values outside the enum
Can allow numeric values outside the enum if you use a numeric enum
Can change the object, immutability opt-in with
readonlyCan't change enum props without
-readonly. Other numeric values outside the enum can beUse
in Enum if possible.Code Snippets
let obj: { [key in MyEnum]: any} =
{ [MyEnum.First]: 1, [MyEnum.Second]: 2 };let obj: { [key in MyEnum]?: any} =
{ [MyEnum.First]: 1 };let obj: { [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj.First = 1;
// Cannot assign to 'First' because it is a read-only property.let obj: { -readonly [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj.First = 1; // workslet obj: { [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj[2] = 1;Context
Stack Overflow Q#44243060, score: 445
Revisions (0)
No revisions yet.