新闻中心

TypeScript 递归获取类字段属性

2025-10-29
浏览次数:
返回列表

typescript 递归获取类字段属性

本文旨在解决 TypeScript 中递归获取类字段属性时遇到的 "Type instantiation is excessively deep and possibly infinite" 错误。通过修改类型定义,特别是针对 `Map` 类型的特殊处理,以及保留字段的可选性,提供了一种避免无限递归并正确获取字段类型的方法。

在 TypeScript 中,使用递归类型定义来处理复杂的数据结构是很常见的。然而,不当的递归类型定义可能导致编译器报错,提示 "Type instantiation is excessively deep and possibly infinite"。这个问题通常发生在类型定义过于复杂,导致编译器无法在合理的深度内完成类型推断时。本文将探讨如何解决这个问题,并提供一个具体的示例,展示如何递归地获取类字段的属性,同时排除函数类型,并保留字段的可选性。

理解问题根源

"Type instantiation is excessively deep and possibly infinite" 错误通常是由于类型定义中的循环依赖造成的。例如,一个类型 A 的定义依赖于类型 B,而类型 B 的定义又依赖于类型 A。如果这种依赖关系没有明确的终止条件,编译器就会陷入无限递归,最终报错。

在处理类字段属性时,如果类包含嵌套的复杂类型(例如,数组、Map、Set 等),并且递归类型定义没有针对这些类型进行特殊处理,就很容易触发这个错误。

解决方案:改进递归类型定义

为了解决这个问题,我们需要改进递归类型定义,使其能够正确处理各种类型,并避免无限递归。以下是一种可行的解决方案:

万相营造 万相营造

阿里妈妈推出的AI电商营销工具

万相营造 168 查看详情 万相营造
  1. 限制递归深度: 虽然 TypeScript 本身没有直接限制递归深度的机制,但可以通过一些技巧来间接实现。例如,可以添加一个类型参数来表示递归深度,并在每次递归调用时递减该参数。当参数达到某个阈值时,停止递归。
  2. 特殊处理 Map 类型: Map 类型是导致无限递归的常见原因。我们需要在递归类型定义中显式地检查 Map 类型,并对其进行特殊处理。一种方法是先检查类型是否为 Map,如果是,则进一步推断键和值的类型,并对值类型进行递归处理。
  3. 保留字段的可选性: 在获取类字段属性时,我们需要保留字段的可选性。这意味着如果一个字段是可选的(使用 ? 标记),那么在递归类型定义中也应该保持其可选性。
  4. 明确终止条件: 递归类型定义必须有一个明确的终止条件。例如,当类型为原始类型(如 string、number、boolean 等)时,停止递归。

代码示例

以下是一个改进后的代码示例,展示了如何递归地获取类字段的属性,同时排除函数类型,并保留字段的可选性:

type DeepWritablePrimitive = undefined | null | boolean | string | number | Function;

type DeepWritable<T> =
  | T extends DeepWritablePrimitive ? T
  : T extends (infer U)[] ? DeepWritable<U>[]
  : T extends Map<any, any> ? (
    T extends Map<infer K, infer V> ? Map<K, DeepWritable<V>> : never
  )
  : T extends Set<infer V> ? Set<DeepWritable<V>>
  : DeepWritableRecord<T>;

type WritableKeys<T> = {
  [P in keyof T]: T[P] extends Function ? never : P
}[keyof T];

type DeepWritableRecord<T> = {
  // need to keep optionality
  [K in keyof Pick<T, WritableKeys<T>>]: DeepWritable<T[K]>
}

class Base {
  set(data?: Partial<DeepWritable<typeof this>>) {
    Object.assign(this, data);
  }
}

class Parent extends Base {
  name?: string;
  arr?: Parent[];
  map?: Map<string, Parent>;
};

const record = new Parent();
record.set({
  // https://github.com/microsoft/TypeScript/issues/34933
  arr: [{
    name: '0'
  }],
  map: new Map([['key', {name: 'map_value'}]])
})
console.log(record.arr);
console.log(record.map?.get('key')?.name);

在这个示例中,DeepWritable 类型定义递归地处理了数组、Map 和 Set 类型,并保留了字段的可选性。WritableKeys 用于排除函数类型的字段。

注意事项

  • 在处理复杂的类型定义时,建议逐步构建类型,并使用 TypeScript 的类型检查器来验证类型的正确性。
  • 如果仍然遇到 "Type instantiation is excessively deep and possibly infinite" 错误,可以尝试简化类型定义,或者使用类型别名来减少类型的嵌套深度。
  • 在某些情况下,可能需要使用类型断言来绕过类型检查器的限制。但是,应该谨慎使用类型断言,因为它可能会导致运行时错误。

总结

通过改进递归类型定义,我们可以解决 TypeScript 中 "Type instantiation is excessively deep and possibly infinite" 错误,并正确地获取类字段的属性。关键在于限制递归深度,特殊处理 Map 类型,保留字段的可选性,并明确终止条件。希望本文能够帮助你更好地理解和解决这个问题。

以上就是TypeScript 递归获取类字段属性的详细内容,更多请关注其它相关文章!


# 就会  # 黄埔sem网站优化推广价格  # 常州市网站公告优化厂家  # seo是什么最便宜  # seo网络优化和帖子  # 汕尾当地的免费网站优化  # 浙江知名网站建设企业  # seo免费挂链  # 安阳抖音seo公司排名  # 怎么加入头条号网站推广  # 网站做好以后怎么优化  # 是一种  # git  # 是一个  # 质量检测  # 报错  # 工作流  # 解决这个问题  # 数据结构  # 可选  # 递归  # microsoft  # github  # typescript 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: Node.js 中使用 node-cron 实现定时 API 数据抓取与处理  免费抖音短视频入口_抖音网页版短视频免费通道  小米14应用无法联网原因分析_小米14网络权限修复  C++如何进行游戏物理模拟_使用Box2D库为C++游戏添加2D物理效果  Bilibili动漫最新防封地址发布-Bilibili动漫2025年最稳正版入口推荐  163邮箱注册官网 免费申请163个人邮箱  cad怎么合并重叠的线段_cad清理重复重叠线条的操作方法  Tailwind CSS line-clamp 布局问题解析与修复指南  c++ 获取系统当前时间 c++时间戳获取方法  QQ邮箱网页版入口登录 QQ邮箱在线邮箱官方通道  MinIO大规模对象列表性能瓶颈深度解析与外部元数据管理策略  Win11怎么关闭快速启动_Win11彻底关机设置教程  邮政快递包裹最新位置 邮政快递实时追踪入口  R星幕后开发视频泄露 包含《GTA6》等多款大作  曝R星经典之作开发图 设计简陋但信息密集!  C++如何操作大型数据集_使用C++流式处理(Streaming)技术避免一次性加载大文件  漫蛙2正版漫画站 漫蛙2网页版快速访问入口  taptap防沉迷怎么解除 taptap解除健康系统限制说明【2025最新】  格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施  漫蛙漫画官方主页入口 漫蛙MANWA网页直达访问链接  qq浏览器如何查看和导出已保存的密码 qq浏览器密码管理器数据备份教程  cad如何更改注释性对象的比例_cad注释性比例调整方法  抖音网页版平台入口 抖音网页版官网在线访问教程  漫蛙2(台版)官方入口地址 漫蛙2(台版)正版漫画网页端  优化LangChain文档加载与ChromaDB集成:解决多文档处理与分块问题  sublime如何处理大型CSV文件的列对齐_sublime高级表格编辑插件指南  LocoySpider如何部署到云服务器_LocoySpider云部署的远程配置  深入理解Go语言中Map值与方法接收器的交互:为什么需要临时变量  Python中高效且防溢出的双曲正弦计算:基于对数空间的优化策略  Composer的 "licenses" 命令如何帮助你遵守开源协议_检查项目依赖的许可证合规性  抖音商城签到领现金是真的吗_抖音商城签到奖励与提现说明  126邮箱网页版官方入口 126邮箱账号在线登录平台  如何将HTML表格多行数据保存到Google Sheets  Sublime怎么配置Nim语言环境_Sublime Nim代码高亮与补全  PHP表单数据传递:如何通过隐藏输入字段获取动态ID  抖音创作助手登录入口_抖音创作辅助工具官网直达  漫画星球免费下拉式入口 漫画星球免费漫画在线阅读网站  J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析  一加Ace 6T实拍样张首次公布!李杰:主摄实力完全看齐4K档性能旗舰  C++ typeid如何获取类型信息_C++ RTTI运行时类型识别用法  字由网在线版登录地址 字由网网页版安全入口  解决 Vaadin 8 中大文件音频播放与定位时出现的 IOException  蛙漫官网漫画入口地址_蛙漫在线畅读无广告弹窗  KFC套餐升级怎么获取优惠代码_KFC套餐升级活动与优惠代码获取方法  漫蛙manwa2最新登录网址_漫蛙manwa2手机网页版入口  ArrayList与LinkedList核心操作的Big-O复杂度分析  妖精漫画网页版登录入口免费_妖精漫画官网主页直接阅读漫画  《刺客信条4:黑旗》重制版新细节曝光:无缝加载 地图更细致!  163邮箱登录密码 163邮箱忘记密码找回  优化Django表单:提交验证失败后保留用户输入 

搜索