首页 > 解决方案 > 为什么`typeof Map2` 返回“数字”的提示?

问题描述

代码很简单。这是 TS 或 VScode 的错误吗?

interface Map2<T> {
  [key: string]: T;
}
type XXX = keyof Map2<string>
     //hint~ type XXX = string | number
interface Map2<T> {
  [key: string]: T;
}
type XXX = keyof Map2<boolean>
     //hint~ type XXX = string | number

标签: typescript

解决方案


这不是一个错误。这种行为是在 TypeScript 2.9 中引入的。从文档中:

给定一个对象类型Xkeyof X解析如下:

  • 如果X包含字符串索引签名,keyof X是 , 和表示符号类属性的文字类型的stringnumber

这样做的原因是为了处理 TypeScript 具有number键概念的事实,尽管 JavaScript 确实没有。但是 TypeScript假装number是对象的有效键类型。

JavaScript 中的所有非符号键实际上都是字符串,甚至是数组的索引键。(例如,Object.keys(["a","b"])返回["0", "1"])当您使用数字索引到数组时,如在中arr[0],索引首先被强制转换为字符串并被视为arr["0"]。因此,具有string索引的对象仍然可以被视为具有数字键的类数组对象,因为string当您使用它们时它们将被强制转换。

在一个完全健全和理想的 TypeScript 类型系统中,会有一个名为NumericString的类型,它是string对应于 的String(n)所有number值的输出的子类型n。当你用它索引一个对象时,TypeScript 会自动强制number执行。NumericString在那个假设的世界中,string索引只是一个string索引,您仍然可以像使用数组一样使用它,并且没有任何人想要添加numberkeyof {[k: string]: any}.

然而,在这个世界中,数组在 TypeScript 中表示为具有number键,如果您只将键视为非键,则会出现问题。你会得到是。他们没有通过删除索引并将它们更改为来修复它,而是通过添加作为伪子类型来解决它,该伪子类型仅在您查看对象键时出现。stringnumberkeyof {[n: number]: any}nevernumberNumericStringnumberstring

所以,你去吧。这是故意的。如果您不想在 中看到numberstring可以使用建议的解决方法替换keyof XExtract<keyof X, string>.

好的,希望有帮助;祝你好运!


推荐阅读