TypeScript 对象的 keyof 的奇怪类型

问题描述 投票:0回答:1

在对象上使用

keyof
类型运算符时,我很难理解 TypeScript 的类型。 看看下面的例子

type TypeA = { [k: number]: boolean };
type AKey = keyof TypeA;
//   ^? type AKey = number

type TypeB = { [k: string]: boolean };
type BKey = keyof TypeB;
//   ^? type BKey = string | number

TypeScript 文档 包含一条注释,内容如下:

请注意,在此示例中,

keyof { [k: string]: boolean }
string | number
— 这是因为 JavaScript 对象键始终强制转换为字符串,因此 obj[0] 始终与 obj["0"] 相同。

这看起来似乎应该是完全相反的。

AKey
应该是数字(因为它们总是被强制转换为字符串),而
BKey
应该只是一个字符串,因为该类型不允许数字。

如果这还不够令人困惑,那么使用

Record<>
时同样不成立。 这似乎是因为定义使用
in
而不是
:
:

type Record<K extends string | number | symbol, T> = { [P in K]: T; }

type TypeC = { [k in number]: boolean }; // Record<number, boolean>
type CKey = keyof TypeC;
//   ^? type CKey = number

type TypeD = { [k in string]: boolean }; // Record<string, boolean>
type DKey = keyof TypeD;
//   ^? type DKey = string

所有类型都允许使用数字和字符串作为键,因此类型定义似乎不会以任何方式影响:

const value: TypeA | TypeB | TypeC | TypeD = {
  0: false,
  "1": true,
};

谁能帮我理解这种类型的马戏团?

typescript typescript-typings typeof
1个回答
0
投票

keyof
运算符应用于映射类型和具有索引签名的类型时的行为在microsoft/TypeScript#23592的实现拉取请求中指定。规则是:

给定一个对象类型

X
keyof X
的解析如下:

  • 如果
    X
    包含字符串索引签名,则
    keyof X
    string
    number
    和表示类似符号属性的文字类型的并集,否则
  • 如果
    X
    包含数字索引签名,则
    keyof X
    number
    和表示类似字符串和类似符号属性的文字类型的并集,否则
  • keyof X
    是表示类似字符串、类似数字和类似符号属性的文字类型的联合。

TypeScript 将

number
类型的数字键视为
string
类型键的子类型(这是支持数组索引的方便虚构;对象键从来都不是真正的
number
,而是数字 strings。但我离题了,有关更多信息,请参阅具有索引签名的 keyof 类型运算符

)。这意味着每个数字键实际上都是字符串键,但并非每个字符串键都是数字键。具有数字索引签名的对象并不声称支持每个字符串键,而具有字符串索引签名的对象确实声称支持每个字符串键,其中也包括数字键。

至于 
keyof Record<string, T>
 的行为差异是 
string
keyof {[k: string]: T}
string | number,映射类型的行为在拉取请求中没有改变,因此可以通过这种方式确认它是。至于为什么会这样,那就很难说清楚了。我能找到的最接近规范的答案是 TS 开发团队负责人在 microsoft/TypeScript#31013 中的评论:

至于该行为不适用于映射类型,那么,产生不同的行为就是我们添加不同语法的原因。 如需更深入的研究,请从

#23592 开始

因此,即使

keyof {[P in K]: T}

K
,大概 
K
 成为 
string
 也很重要,而它与 
keyof {[k: string]: T}
 不一致的原因是因为不同的语法允许在两种行为之间进行选择。我猜。无论如何,它指向 microsoft/TypeScript#23592。

© www.soinside.com 2019 - 2024. All rights reserved.