You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript:为联合类型嵌套对象添加属性的通用解决方案

解决TypeScript联合类型动态添加属性的类型不匹配问题

核心问题是TypeScript无法自动识别联合类型里name和attrs的关联关系。你写的逻辑没问题,但返回对象时,TS会把name推断为"test1" | "test2",attrs推断成两个扩展后的对象的联合,而Test<true>是一组name和attrs一一对应的对象联合,不是两个独立字段的联合,所以类型不匹配报错。

下面给出两种无需逐个判别类型的通用方案:

方案1:重构类型+泛型生成(更易维护)

先定义不带id的基础联合类型,再通过泛型一键生成带/不带id的版本,最后用泛型让TS追踪单个联合成员:

// 定义不带id的基础类型,后续新增类型只需要加在这里
type BaseTest = 
  | { name: "test1"; attrs: { t1: boolean } }
  | { name: "test2"; attrs: { t2: string } };

// 通过泛型生成带/不带id的Test类型
type Test<T extends boolean> = BaseTest extends infer U 
  ? U extends { name: infer N; attrs: infer A }
    ? { 
        name: N;
        attrs: A & { id: T extends true ? string : never };
      }
    : never
  : never;

// 泛型函数处理单个联合成员,自动匹配返回类型
const addId = <T extends Test<false>>(node: T, id: string): Test<true> => {
  return { ...node, attrs: { ...node.attrs, id } } as Test<true>;
};

方案2:类型转换工具(兼容原类型定义)

如果不想改动原有的类型结构,可以写一个类型转换工具,把Test<false>的成员转为对应的Test<true>成员:

// 保持你原来的类型定义不变
type Test1<T extends boolean> = {
  name: "test1";
  attrs: { t1: boolean; id: T extends true ? string : never };
};

type Test2<T extends boolean> = {
  name: "test2";
  attrs: { t2: string; id: T extends true ? string : never };
};

type Test<T extends boolean> = Test1<T> | Test2<T>;

// 类型转换:将Test<false>成员转为Test<true>对应成员
type ToTestTrue<T extends Test<false>> = 
  T extends Test1<false> ? Test1<true> : 
  T extends Test2<false> ? Test2<true> : never;

// 泛型函数确保输入和输出类型一一对应
const addId = <T extends Test<false>>(node: T, id: string): ToTestTrue<T> => {
  return { name: node.name, attrs: { ...node.attrs, id } } as ToTestTrue<T>;
};

这两种方案都不需要依赖any,而且不管联合类型新增多少成员,都不用修改函数逻辑,直接复用类型定义即可。

内容的提问来源于stack exchange,提问作者Quinn Straus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 00:13:09