Jest自动Mock接口作用于Window/Element触发TS2589过深报错如何解决?
问题根因
- 原
MockedInterface类型无递归终止条件:string、number、boolean等原始值也会进入递归逻辑,遇到Element、Window这类存在自引用属性的内置类型时,会触发无限递归,最终抛出Type instantiation is excessively deep and possibly infinite.ts(2589)错误 - 多余的类型交叉操作:
& T[K]会额外增加TS类型计算开销,进一步拉长类型解析耗时 - 无深度兜底逻辑:对于循环引用的结构没有停止递归的兜底机制,是触发报错的直接原因
修复后的实现
type JestMock<T, Y extends Array<any>> = (...args: Y) => T export interface CalledWithMock<T, Y extends Array<any>> extends JestMock<T, Y> { calledWith: (...args: Y) => JestMock<T, Y>; } // 辅助类型:用于减少递归深度计数,可根据需要延长数组长度支持更深的递归 type Decrease<N extends number> = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9][N]; // 泛型参数Depth可自定义递归深度,默认5层满足绝大多数Mock场景 export type MockedInterface<T, Depth extends number = 5> = Depth extends 0 ? T : T extends (...args: infer A) => infer B ? CalledWithMock<B, A> : T extends object ? { [K in keyof T]: MockedInterface<T[K], Decrease<Depth>> } : T;
优化说明
- 新增递归终止判断:非对象/函数的原始类型直接返回原值,避免不必要的递归计算
- 新增深度兜底逻辑:默认最多递归5层,超过深度直接返回原类型,彻底解决循环引用导致的无限递归问题
- 移除多余的交叉类型操作:
CalledWithMock已经继承了原函数的调用签名,对象类型也会保留所有原属性,返回结果天然兼容原类型,无需额外交叉增加计算负担 - 深度可自定义:如果有更深层级的Mock需求,可修改
Depth默认值,或者延长Decrease类型的数组长度即可
内容的提问来源于stack exchange,提问作者David Alsh
相关产品推荐
相关产品推荐

