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
相关产品推荐
相关产品推荐

