TypeScript联合类型中嵌套对象的类型安全处理方案问询
实现简洁且类型安全的嵌套对象处理函数
假设我们有三个嵌套对象类型Basic、Extra、Extra2,它们共享部分configs配置,但嵌套结构存在差异。目前有两个功能完全一致的函数:
test写法简洁,但因嵌套对象的结构差异触发TypeScript类型错误test2严格符合TypeScript规范,但代码过于冗长
先定义示例类型和问题函数:
// 共享的配置类型 type SharedConfigs = { timeout: number; retries: number; }; // 基础类型 type Basic = { configs: SharedConfigs; type: 'basic'; }; // 扩展类型1 type Extra = { wrapper: { configs: SharedConfigs; }; type: 'extra'; }; // 扩展类型2 type Extra2 = { nested: { inner: { configs: SharedConfigs; }; }; type: 'extra2'; }; // 简洁但类型报错的test函数 function test(obj: Basic | Extra | Extra2) { // TypeScript报错:无法确定obj的具体结构,无法直接访问嵌套的configs const configs = obj.configs || obj.wrapper?.configs || obj.nested?.inner?.configs; console.log(configs.timeout, configs.retries); } // 合规但冗长的test2函数 function test2(obj: Basic | Extra | Extra2) { let configs: SharedConfigs; if (obj.type === 'basic') { configs = obj.configs; } else if (obj.type === 'extra') { configs = obj.wrapper.configs; } else { configs = obj.nested.inner.configs; } console.log(configs.timeout, configs.retries); }
方案一:自定义类型守卫函数
把类型判断逻辑封装成独立的类型守卫函数,主函数可以用简洁的三元表达式实现:
function isBasic(obj: Basic | Extra | Extra2): obj is Basic { return obj.type === 'basic'; } function isExtra(obj: Basic | Extra | Extra2): obj is Extra { return obj.type === 'extra'; } function isExtra2(obj: Basic | Extra | Extra2): obj is Extra2 { return obj.type === 'extra2'; } function test3(obj: Basic | Extra | Extra2) { const configs = isBasic(obj) ? obj.configs : isExtra(obj) ? obj.wrapper.configs : obj.nested.inner.configs; console.log(configs.timeout, configs.retries); }
方案二:封装提取逻辑到辅助函数
把提取configs的逻辑单独抽成辅助函数,主函数只需要调用该函数即可,写法简洁且类型安全:
function getConfigs(obj: Basic | Extra | Extra2): SharedConfigs { if ('configs' in obj) { return obj.configs; } else if ('wrapper' in obj) { return obj.wrapper.configs; } else { return (obj as Extra2).nested.inner.configs; } } function test4(obj: Basic | Extra | Extra2) { const configs = getConfigs(obj); console.log(configs.timeout, configs.retries); }
方案三:利用区分联合类型的映射写法
因为三个类型都有type这个区分字段,可以直接用对象映射的方式快速匹配对应结构,写法最简洁:
function test5(obj: Basic | Extra | Extra2) { const configs = { basic: obj.configs, extra: (obj as Extra).wrapper.configs, extra2: (obj as Extra2).nested.inner.configs }[obj.type]; console.log(configs.timeout, configs.retries); }
总结
- 类型守卫函数适合类型较多、需要复用判断逻辑的场景
- 辅助函数适合把提取逻辑封装隔离,主函数聚焦业务逻辑
- 区分联合类型的映射写法最简洁,适合有明确区分字段的联合类型
内容的提问来源于stack exchange,提问作者Yunhai
相关产品推荐
相关产品推荐

