TypeScript如何定义可自引用且兼容其他值的嵌套对象类型
TypeScript嵌套对象类型定义属性访问报错修复
问题场景
需要为任意层级的嵌套对象定义TypeScript类型,初始写法给变量赋值时校验正常,但访问对象属性时触发类型报错。
初始类型定义与报错代码:
type NestedObject = { [key: string]: NestedObject | string; } const obj: NestedObject = { a: '123', b: { b_a: { b_a_a: '456' }, b_b: '789' } }; function ABC(myNestedObject: NestedObject) { const nestedObject: NestedObject = { // 报错:Property 'fail' does not exist on type 'string | NestedObject'. 'failProperty': myNestedObject.properties.fail }; }
曾尝试通过条件类型判断值是否继承自string优化定义,但写法无法生效:
type NestedObject = { [K in NestedObject]: NestedObject[K] extends string ? string : NestedObject; }
报错原因
- 初始
NestedObject使用字符串索引签名,TS会判定任意key对应的属性值类型都是NestedObject | string联合类型,静态检查阶段无法确定访问的属性值是字符串还是嵌套对象,直接在值上访问子属性时,TS会识别到string类型上不存在对象属性,抛出类型错误。 - 自写的条件类型属于非法循环定义:
[K in NestedObject]语法要求in后面跟键名的联合类型,NestedObject本身是对象结构类型,不是合法的键集合,因此写法直接失效。
修复方案
根据业务场景二选一即可:
- 嵌套对象结构固定时:放弃通用索引签名,直接定义精确匹配结构的类型,TS可自动推导每个属性的准确类型,不会出现联合类型报错。
// 匹配示例obj结构的精确类型 type DefinedNestedObj = { a: string; b: { b_a: { b_a_a: string; }; b_b: string; } } - 嵌套对象结构未知、需要兼容任意层级时:访问子属性前先做类型收窄,判断当前值不是字符串类型后再访问属性,符合TS类型检查规则。可以封装通用类型守卫简化判断:
type NestedObject = { [key: string]: NestedObject | string; } // 类型守卫:判断值是否为嵌套对象 function isNestedObject(val: unknown): val is NestedObject { return typeof val === 'object' && val !== null; } function ABC(myNestedObject: NestedObject) { const properties = myNestedObject.properties; const nestedObject: NestedObject = { // 收窄类型后安全访问属性 'failProperty': isNestedObject(properties) ? properties.fail : '' }; }
内容的提问来源于stack exchange,提问作者pianoman
相关产品推荐
相关产品推荐

