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

TypeScript泛型递归超9就报2589错误 官方限50为何提前触发

问题描述

我实现了一个可生成JSON键值列表所有可能组合的泛型类型,还额外添加了递归深度限制逻辑,对应代码如下:

type EditAction<T,P extends keyof T,Prev extends any[]> = {
    data : T[P]
    id : [...Prev, P]
    prev : Prev
}

type EditActions<T, Depth extends number = 50, Prev extends any[] = []> = {
    [P in keyof T] : T[P] extends JsonType 
        ? (Prev["length"] extends Depth
            ? EditAction<T,P,Prev>
            : (EditAction<T,P,Prev> | EditActions<T[P],Depth,[...Prev,P]>)) 
        : EditAction<T,P,Prev>
}[keyof T]

但即便我添加了深度限制逻辑,只要将Depth参数设为大于9就会触发TypeScript报错,按照官方说明TypeScript类型递归的最大限制为50,请问为何会触发如下报错:

Type instantiation is excessively deep and possibly infinite.ts(2589)
(property) payload: EditActions<T, 50, []>
原因解答
  • 2589报错的判定逻辑不只有递归深度这一个维度:除了官方说明的默认50层递归深度限制外,TypeScript还会对类型实例化的总计算量、生成的类型复杂度做阈值限制。你当前的实现每递归一层,都会将当前层级的所有键对应的EditAction和下一层级返回的EditActions联合类型做合并,最终生成的联合类型成员数量是指数级增长的。比如每层对象有2个键,10层递归就会生成超过1000个联合成员,在Depth设为10左右就会触碰到实例化开销阈值,和50层的递归深度限制没有关系。
  • 你的深度终止判断逻辑额外增加了计算开销:用Prev["length"] extends Depth作为递归终止条件,需要逐层级比对元组长度,同时每一层都要构造新的[...Prev, P]元组存储路径,这部分操作比单纯的数字泛型计数开销更高,进一步降低了触发报错的深度阈值。
  • 如果你的JsonType定义包含any、unknown或者自引用的递归结构,也可能导致TS无法正确识别递归终止边界,提前触发复杂度报错。
优化方案
  • 可以将深度计数替换为单独的数字泛型,减少元组构造和长度比对带来的额外开销
  • 若使用TS 4.5及以上版本,可将类型改写为尾递归形式,利用TS内置的尾递归类型优化特性,大幅降低实例化开销
  • 收窄JsonType的定义范围,明确排除不需要遍历的类型,减少冗余的递归遍历操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 22:24:03