You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中WriteableKeys类型为何返回'b'而非'b'|never?

为什么WriteableKeys返回'b'而非'b'|never?

咱们一步步拆解代码逻辑,搞清楚背后的原理:

1. 先看懂IfEquals的作用

这个类型的核心是精准判断两个类型是否完全等价(包括readonly这类修饰符)。普通的X extends Y && Y extends X没法区分带readonly和不带readonly的同结构类型,但用泛型函数的条件判断可以做到:

type IfEquals<X, Y, A = X, B = never> = 
  (<T>() => T extends X ? 1 : 2) extends 
  (<T>() => T extends Y ? 1 : 2) ? A : B

如果X和Y的结构完全一致(包括readonly修饰符),那两个泛型函数类型会被认为等价,返回A;否则返回B。

2. WriteableKeys的中间结果

当你写{[K in keyof T]-?: IfEquals<{[Q in K]: T[K]}, {-readonly [Q in K]: T[K]}, K>}时,会遍历输入类型的每个键:

  • 针对readonly a: number:
    • {[Q in K]: T[K]}是{readonly a: number}
    • {-readonly [Q in K]: T[K]}是{a: number}
      这两个类型不等价,所以IfEquals返回never
  • 针对b: string:
    • 两个类型都是{b: string}(本来就没有readonly,去掉后结构不变)
      类型等价,所以IfEquals返回键名'b'
      最终得到的中间类型是:{readonly a: never; b: 'b'},这部分你已经理解。

3. 索引访问类型与never的特性

当你在后面加上[keyof T]时,这是索引访问类型,意思是用keyof T(也就是'a'|'b')去索引前面的对象类型,得到的是所有对应值的联合类型:

{readonly a: never; b: 'b'}['a'|'b'] = never | 'b'

这里的关键是never在联合类型中会被自动吸收——因为never表示不存在的类型,当它和其他类型联合时,相当于没有这个类型,所以never | 'b'最终会简化为'b'。

这就是为什么最终结果是'b'而不是'b'|never的原因。


内容的提问来源于stack exchange,提问作者lykl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 22:47:38