为何TypeScript中`T[keyof T] extends Function`可执行?递归类型无循环?
为什么DeepReadonly递归不会无限循环?
先看你的代码:
type DeepReadonly<T> = { readonly [k in keyof T]: T[k] extends Function ? T[k] : DeepReadonly<T[k]> } type X1 = {a: string}; type A = DeepReadonly<X1>
你疑惑的是当传入string类型到DeepReadonly时,为什么不会无限递归?核心原因有两个:
基础类型的递归收敛:当
T是string这类基础类型时,虽然keyof string会返回它的内置属性(比如toString、charAt,还有索引签名number),但在处理映射类型的属性值时:- 对于
Function类型的属性(比如toString),条件判断会直接返回原函数类型,不会递归; - 对于索引签名
number对应的string类型,虽然会触发DeepReadonly<string>,但TypeScript会识别到这是循环引用且不会产生新类型结构的情况——因为DeepReadonly<string>最终的结构和string本身完全兼容(基础类型没有可修改的属性,readonly修饰符对它无效),所以会直接终止递归,返回string类型。
- 对于
TypeScript的惰性求值与递归优化:TypeScript对条件类型和递归类型采用惰性求值,只有在需要实际解析类型结构时才会展开。对于这种递归到基础类型的场景,TypeScript会判断继续展开不会得到新的信息,因此会停止递归,避免无限循环。
实际验证的话,你可以查看A的类型推断结果,它会是{ readonly a: string },完全符合预期,没有出现无限递归的问题。
内容的提问来源于stack exchange,提问作者coatP
相关产品推荐
相关产品推荐

