enum
类型可以用作key
类型吗?目前似乎只有这种声明,其中key
可以是number
或string
类型。是否可以创建类似于以下示例的内容:enum MyEnum
{
First,
Second
}
var layer:{[key:MyEnum]:any};
enum
类型可以用作key
类型吗?目前似乎只有这种声明,其中key
可以是number
或string
类型。是否可以创建类似于以下示例的内容:enum MyEnum
{
First,
Second
}
var layer:{[key:MyEnum]:any};
自2018年起,在Typescript中有一种更简便的方式,无需使用keyof typeof
:
let obj: { [key in MyEnum]: any} =
{ [MyEnum.First]: 1, [MyEnum.Second]: 2 };
不需要包含所有的键:
let obj: { [key in MyEnum]?: any} =
{ [MyEnum.First]: 1 };
in
和 keyof typeof
之间的区别,请继续阅读。
in Enum
vs keyof typeof Enum
in Enum
编译为枚举值,而keyof typeof
编译为枚举键。
使用keyof typeof
,你无法更改枚举属性:
let obj: { [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj.First = 1;
// Cannot assign to 'First' because it is a read-only property.
-readonly
,否则...let obj: { -readonly [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj.First = 1; // works
let obj: { [key in keyof typeof MyEnum]?: any} = { First: 1 };
obj[2] = 1;
keyof typeof
将编译为:
{
[x: number]: any;
readonly First?: any;
readonly Second?: any;
}
[x: number]
和readonly
属性。这个[x: number]
属性在string enum中不存在。in Enum
,你可以改变对象: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 default
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; }'.
{
0?: any;
1?: any;
}
0
和1
。keyof typeof
那样的意外情况。enum MyEnum
{
First = 1,
Second = "YES"
}
let obj: { [key in MyEnum]?: any} = { [MyEnum.First]: 1, [MyEnum.Second]: 2 };
obj[1] = 0;
obj["YES"] = 0;
这里的类型是:
{
1?: any;
YES?: any;
}
使用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.
... 这使得这些键 只读
:
{
readonly 1?: any;
readonly 2?: any;
}
in Enum |
keyof typeof Enum |
---|---|
编译为枚举值 | 编译为枚举键 |
不允许超出枚举范围的值 | 如果使用数字枚举,可以允许超出枚举范围的数值 |
可以更改对象,通过readonly 实现不可变性 |
无法在没有-readonly 的情况下更改枚举属性。其他超出枚举范围的数值可以被更改 |
尽可能使用in Enum
。如果您的代码库使用keyof typeof Enum
,请注意这些陷阱。
let layer:{[key in keyof typeof MyEnum]: any}
自Typescript 2.1版本起,可以使用keyof
关键字。有关详细信息,请参阅TypeScript文档。
仅使用keyof
枚举无法正常工作(您将获得enum
类型的键而不是枚举常量),因此您必须键入keyof typeof
。{[key in keyof typeof MyEnum]?: any}
(?
表示某些枚举的缺失是可以接受的)。 - Aidin计算属性名称必须是“字符串”、“数字”、“符号”或“任何类型”
。 - Mohamed Abu Galalalet layer: Partial<Record<MyEnum, unknown>>;
我有同样的问题,我想让下面的代码段正常运行。
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
从这个问题的其他答案开始,我得到了以下内容:
type myType = {[key in keyof typeof MyEnum]: number};
但是它会提示缺少 "yyy" 的 o
。所以我需要告诉它这个对象将只拥有枚举键的一部分,而不是全部。因此我需要添加 ?
,得到:
type myType = {[key in keyof typeof MyEnum]?: number};
在代码的末尾添加了一行修改对象的代码后,它就出现问题了。现在它抱怨通过keyof
继承的类型将其属性设置为readonly
,并且我无法在第一次创建后对其进行更改! :| 事实上,在 Typescript Playground中悬停在myType
上,会显示:
type myType = {
readonly xxx?: number | undefined;
readonly yyy?: number | undefined;
readonly zzz?: number | undefined;
}
现在,要移除不需要的readonly
属性,我发现可以使用:
type myType = {-readonly [key in keyof typeof myEnum1]?: number };
虽然有些丑陋,但是它能够正常工作!
直到我尝试了Typescript Utility Types,才找到了我想要的东西!
type myType = Partial<Record<keyof typeof MyEnum, number>>;
:)
myType
值必须具有相同的类型(在你的例子中是 number
)。我想能够做类似这样的事情:type myType = { readonly xxx?: number; readonly yyy?: string; }
你觉得这可能吗? - SudoPlzPartial<Record<MyEnum, number|string>
或 Partial<Record<MyEnum,number>> | { yyy?: string}
可能适合你。 - Aidinundefined
和缺失/可选方面存在问题 -- 请参见 https://github.com/microsoft/TypeScript/issues/13195。最近似乎有所改善(自一个月前起!你可以传递一个标志来捕获它:https://github.com/microsoft/TypeScript/pull/43947) - Aidin对于那些寻求一种获取枚举
的键
而不是值
的方法的人,你只需要将代码从以下更改:
type myType = Partial<Record<MyEnum, number>>;
对此:
type myType = Partial<Record<keyof typeof MyEnum, number>>;
实际上,我没有做任何变通就使它运作了。
以下是一些情况:
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}
需要注意的是,即使 "z1" 运行良好,但由于它是只读的,你以后将无法对其进行修改。你可以使用关键字 -readonly
来移除这个限制。
x1.a=2
x3.a=2
z1.a=2 //error: read only
我创建了一个typescript playground,以便您自行查看不同情况的问题。
摘要
enum Person {
FirstName = 'FirstName',
LastName = 'LastName',
}
// Solution 1
type PersonType1 = { [key in Person]?: string }
const persona1: PersonType1 = {}
persona1[Person.FirstName] = "Bear"
persona1[Person.LastName] = "Belly"
persona1.FirstName = "Bear"
persona1.LastName = "Belly"
// Solution 2
type PersonType2 = Partial<Record<keyof typeof Person, string>>
const persona2: PersonType2 = {}
persona2[Person.FirstName] = "Bear"
persona2[Person.LastName] = "Belly"
persona2.FirstName = "Bear"
persona2.LastName = "Belly"
// Solution 3
type PersonType3 = { -readonly [key in keyof typeof Person]?: string }
const persona3: PersonType3 = {}
persona3[Person.FirstName] = "Bear"
persona3[Person.LastName] = "Belly"
persona3.FirstName = "Bear"
persona3.LastName = "Belly"
// Solution 4 without "-readonly", it does not allow to change.
type PersonType4 = { [key in keyof typeof Person]?: string }
const persona4: PersonType4 = {}
persona4[Person.FirstName] = "Bear" // Cannot assign to 'FirstName' because it is a read-only property.
persona4[Person.LastName] = "Belly" // Cannot assign to 'LastName' because it is a read-only property.
persona4.FirstName = "Bear" // Cannot assign to 'FirstName' because it is a read-only property.
persona4.LastName = "Belly" // Cannot assign to 'LastName' because it is a read-only property.
type PersonTypeX = {
FirstName?: string | undefined;
LastName?: string | undefined;
}
type PersonType4 = {
readonly FirstName?: string | undefined;
readonly LastName?: string | undefined;
}
type Layer = { [key in MyEnum]?: any };
而不是interface Layer { [key in MyEnum]?: any }
- Dávid Leblay