TypeScript递归获取类字段属性遇类型过深错误如何解决?
问题与解决方案
问题背景
尝试实现类的set方法,仅接受类的字段属性(排除函数、保留字段可选性),使用递归泛型处理嵌套结构时,触发Type instantiation is excessively deep and possibly infinite.错误,且不能通过// @ts-ignore忽略(会丢失类型安全)。
原代码问题分析
- 递归循环触发:
Base类的set方法使用DeepWritable<typeof this>,子类Parent继承Base后,typeof this包含继承的set方法;同时Parent的arr字段是Parent[],递归处理时会反复带入包含set方法的类型,导致无限递归。 - 不必要的类型包含:
DeepWritablePrimitive中错误包含了Function,与“排除函数”的需求冲突,且增加了递归复杂度。 - 键过滤逻辑冗余:原
WritableKeys同时处理函数排除和只读属性判断,在递归场景下放大了类型计算压力。
修正后的代码
// 排除所有函数类型的键 type OmitFunctions<T> = { [K in keyof T as T[K] extends Function ? never : K]: T[K] }; // 基础类型定义(排除Function) type DeepWritablePrimitive = undefined | null | boolean | string | number; // 带深度限制的递归泛型,避免无限递归 type DeepWritable<T, Depth extends number[] = []> = Depth['length'] extends 10 ? T : // 限制最大递归深度为10,可按需调整 T extends DeepWritablePrimitive ? T : T extends Array<infer U> ? Array<DeepWritable<U, [...Depth, 0]>> : T extends Map<infer K, infer V> ? Map<K, DeepWritable<V, [...Depth, 0]>> : T extends Set<infer U> ? Set<DeepWritable<U, [...Depth, 0]>> : // 先排除函数键,再递归处理字段 { [K in keyof OmitFunctions<T>]: DeepWritable<OmitFunctions<T>[K], [...Depth, 0]> }; class Base { // 使用this类型,结合OmitFunctions排除自身方法,再做深度可写处理 set(data?: Partial<DeepWritable<OmitFunctions<this>>>): void { Object.assign(this, data); } } class Parent extends Base { name?: string; arr?: Parent[]; }; const record = new Parent(); record.set({ arr: [{ name: '0' }] }); console.log(record.arr);
关键改动说明
- 新增
OmitFunctions<T>:直接过滤掉所有值为函数类型的键,逻辑简洁且避免递归时带入方法类型。 - 递归深度限制:通过
Depth元组参数控制递归深度(默认10层),当达到指定深度时停止递归,避免类型计算溢出。 - 修正
DeepWritable逻辑:- 移除
DeepWritablePrimitive中的Function,明确基础类型范围。 - 处理对象类型时,先通过
OmitFunctions<T>排除函数键,再递归处理字段。
- 移除
set方法参数优化:使用OmitFunctions<this>替代typeof this,直接排除当前实例的所有方法,仅保留字段属性。
内容的提问来源于stack exchange,提问作者incutonez
相关产品推荐
相关产品推荐

