TypeScript如何定义任意深度且最终属性值为string/number的通用对象类型
错误原因
你定义的GenericObject接口使用了索引签名,其返回值是string | number | GenericObject | GenericObject[]联合类型。当你访问object.test2这类属性时,TypeScript无法确定该属性到底是基础值、嵌套对象还是对象数组,因此直接访问下层属性会抛出类型错误。
解决方案
方案1:使用satisfies操作符(推荐,适用于TypeScript 4.9及以上版本)
该方案既可以校验你定义的对象完全符合GenericObject的约束(保证末端值仅为string/number,支持任意层级嵌套),同时不会丢失对象本身的具体结构类型,访问嵌套属性不会触发类型错误。
代码示例:
interface GenericObject { [key: string]: string | number | GenericObject | GenericObject[]; } // 用satisfies校验类型,不直接标注变量类型 const object = { test: 'test', testNum: 2, test2: { test: 'test' }, test3: [ { test: 'test' } ] } satisfies GenericObject; // 访问嵌套属性无报错 object.test2.test; object.test3[0].test;
如果你的对象不符合GenericObject约束(比如末端值出现boolean等非法类型),TypeScript会在校验阶段直接抛出错误,符合你的需求。
方案2:使用类型收窄(适用于必须显式标注变量为GenericObject类型的场景)
如果业务要求你必须把变量的类型显式标注为GenericObject,可以在访问嵌套属性前先做类型判断,收窄属性类型后再访问:
interface GenericObject { [key: string]: string | number | GenericObject | GenericObject[]; } const object: GenericObject = { test: 'test', testNum: 2, test2: { test: 'test' }, test3: [ { test: 'test' } ] } // 收窄test2类型为GenericObject后访问 if (typeof object.test2 !== 'string' && typeof object.test2 !== 'number' && !Array.isArray(object.test2)) { console.log(object.test2.test); } // 收窄test3为数组后再收窄子项类型 if (Array.isArray(object.test3)) { const item = object.test3[0]; if (typeof item !== 'string' && typeof item !== 'number' && !Array.isArray(item)) { console.log(item.test); } }
内容的提问来源于stack exchange,提问作者Ryan Davis
相关产品推荐
相关产品推荐

