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

Flá*_*bôa 8 enums interface typescript typescript2.0

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

enum Enum {
    A = 0,
    B = 1,
}

type EnumMap = {
    [P in Enum]: string;
}
Run Code Online (Sandbox Code Playgroud)

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

enum Enum {
    A = 0,
    B = 1,
}

interface EnumMap {
    [P in Enum]: string;
}
Run Code Online (Sandbox Code Playgroud)

错误是:

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

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


进一步调查,我还发现,在下面的例子中,EnumValues有 type number, 而不是 (我期望的) 0 | 1。再次,为什么会这样?

const Enum = {
    A: 0,
    B: 1
};

type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys];
Run Code Online (Sandbox Code Playgroud)

cap*_*ian 1

关于错误:

interface EnumMap {
    [P in Enum]: string;
}
Run Code Online (Sandbox Code Playgroud)

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

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

key(Enum) // error
Run Code Online (Sandbox Code Playgroud)

而且,enum还有特殊的行为。

看这个例子:

const enm = (t: Enum) => t

// Argument of type 'typeof Enum' is not assignable to parameter of type 'Enum'
enm(Enum) // error
Run Code Online (Sandbox Code Playgroud)

Enum因此,甚至和之间也存在差异typeof Enum

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

interface EnumMap {
    [P in 'a'|'b']: string; // error
}
Run Code Online (Sandbox Code Playgroud)

因此,它与 TS 限制有关,而不是与枚举有关。

至于第二种情况:

const Enum = {
    A: 0,
    B: 1
};

type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys];
Run Code Online (Sandbox Code Playgroud)

这是因为它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
Run Code Online (Sandbox Code Playgroud)