使用枚举键入接口字段的索引签名?

Posted

技术标签:

【中文标题】使用枚举键入接口字段的索引签名?【英文标题】:Use an enum to type an index signature of an interface field? 【发布时间】:2019-04-29 17:27:04 【问题描述】:

我可以用如下的对象类型表示法来描述索引类型限制:

enum Enum 
    A = 0,
    B = 1,


type EnumMap = 
    [P in Enum]: string;

但是,令人惊讶的是,在接口中使用索引表示法时似乎不可能做到这一点:

enum Enum 
    A = 0,
    B = 1,


interface EnumMap 
    [P in Enum]: string;

错误是:

计算属性名称的类型必须为“字符串”、“数字”、“符号”或“任意”。

有什么理由会这样吗?根据定义,TypeScript 中的枚举只能有字符串或数字值(甚至两者都有,但不推荐这样做),我认为枚举本身对于它列出的所有值都可以像联合类型一样工作。


进一步调查,我还发现,在以下示例中,EnumValues 的类型为 number,而不是(我期望的)0 | 1。再说一遍,为什么会这样?

const Enum = 
    A: 0,
    B: 1
;

type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys];

【问题讨论】:

我相信这些答案会对您有所帮助:***.com/questions/64970414/… 和 ***.com/questions/37233735/… 【参考方案1】:

关于错误:

interface EnumMap 
    [P in Enum]: string;

枚举是 TypeScript 中的一种特殊数据结构,它不能分配给 string | number | symbol。 考虑这个例子:

const key = <T extends string | number | symbol>(t: T) => t

key(Enum) // error

另外,enum 有特殊行为。

看这个例子:

const enm = (t: Enum) => t

// Argument of type 'typeof Enum' is not assignable to parameter of type 'Enum'
enm(Enum) // error

所以即使Enumtypeof Enum 之间也存在差异。

让我们回到我们的问题。 在TS 4.4 之前,您不得在接口中使用联合作为索引签名。 考虑这个没有enum的例子:

interface EnumMap 
    [P in 'a'|'b']: string; // error

因此它是关于 TS 限制而不是关于枚举。

至于第二种情况:

const Enum = 
    A: 0,
    B: 1
;

type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys];

这是因为const Enum 是可变的。

为了获得1|0,你应该让它不可变:

const Enum = 
    A: 0,
    B: 1
 as const; // special syntax

type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys]; // 0 | 1

【讨论】:

以上是关于使用枚举键入接口字段的索引签名?的主要内容,如果未能解决你的问题,请参考以下文章

枚举类型

打字稿:类型“”没有索引签名

如何创建具有索引签名和不同类型的固定属性的 TypeScript 接口?

如何使用映射类型删除索引签名

如何使用 JSDoc 记录符号索引签名以符合打字稿?

低基数字段的索引效率