新闻中心
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
查看详情
- 限制递归深度: 虽然 TypeScript 本身没有直接限制递归深度的机制,但可以通过一些技巧来间接实现。例如,可以添加一个类型参数来表示递归深度,并在每次递归调用时递减该参数。当参数达到某个阈值时,停止递归。
- 特殊处理 Map 类型: Map 类型是导致无限递归的常见原因。我们需要在递归类型定义中显式地检查 Map 类型,并对其进行特殊处理。一种方法是先检查类型是否为 Map,如果是,则进一步推断键和值的类型,并对值类型进行递归处理。
- 保留字段的可选性: 在获取类字段属性时,我们需要保留字段的可选性。这意味着如果一个字段是可选的(使用 ? 标记),那么在递归类型定义中也应该保持其可选性。
- 明确终止条件: 递归类型定义必须有一个明确的终止条件。例如,当类型为原始类型(如 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表单:提交验证失败后保留用户输入


2025-10-29
浏览次数:次
返回列表
| 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);