字符串型索引签名的禁止数字属性

时间:2020-06-22 01:00:44

标签: typescript

假设我们有一个类似的类型定义

type Foo = {
    [_: string]: number
}

但是我们可以将具有编号属性的对象分配给该类型:

const foo: Foo = {
    10: 42
}

问题:是否有任何方式(编译器选项)禁止这种行为?也就是说,我想禁止将带编号的属性分配给字符串型索引签名。

(注) The "indexable types" section of the official typescript handbook说:“使用数字索引时,JavaScript实际上会在将其索引到对象之前将其转换为字符串”,我知道这就是为什么要接受此类分配的原因。我想知道如何解决这个问题。

1 个答案:

答案 0 :(得分:2)

来自the documentation you cited

可以同时支持两种类型的索引器,但是从数字索引器返回的类型必须是从字符串索引器返回的类型的子类型。

考虑the never type

never类型是每种类型的子类型,并且可以分配给每种类型;但是,没有任何类型是never的子类型或可分配给never本身的子类型。

这表明您可以将Foo重新定义为:

type Foo = {
    [_: string]: number
    [_: number]: never
}

这意味着:所有string值的键都应具有number属性类型,而所有number值的键都应具有never属性类型。由于您永远无法创建有效的never类型(没有可分配的类型),因此任何尝试使用数字键的操作都会给您带来错误:

const goodFoo: Foo = {
    a: 1,
    b: 2,
    c: 3
}

const badFoo: Foo = {
    eight: 8,
    nine: 9,
    10: 42 // error!
    // number is not assignable to never
};

对我很好。请注意,这也具有禁止“数字字符串索引”的副作用:

const alsoBad: Foo = { // error!
    eight: 8,
    nine: 9,
    "10": 42 
}
//   Property '"10"' is incompatible with index signature.

希望这没关系,因为正如您指出的,在运行时{10: 42}{"10": 42}是同一件事。

希望能为您提供一些指导;祝你好运!

Playground link to code