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

TypeScript合并多对象时,如何检测重复键并抛出错误?

合并对象时检测重复键并触发TypeScript错误

现有两个对象:

obj A

const A = {
  resetPassword: "/supplier/auth/reset-password",
  login: "/supplier/auth/login",
};

obj B

const B = {
  selfInitiate: "/supplier/actions/request",
  getEmpanelmentReport: "/supplier/empanelment/report",
  getFormData: "/supplier/empanelment/form/",
  formSubmit: "/supplier/empanelment/submit/",
  login: "duplicate login"
};

需求是将这两个对象合并为一个所有键均为只读的对象C,目标类型定义如下:

type SUPPLIER_ROUTE = {
  readonly selfInitiate: string;
  readonly getEmpanelmentReport: string;
  readonly getFormData: string;
  readonly formSubmit: string;
  readonly resetPassword: string;
  readonly login: string;
};

但直接使用扩展运算符合并时:

const C: SUPPLIER_ROUTE = {
  ...A,
  ...B
};

TypeScript不会因为login键重复而抛出错误,需要实现合并时若存在重复键则触发类型错误的逻辑。


实现方案

1. 定义重叠键检测类型

创建一个类型工具NoOverlap,当两个类型存在共同键时返回never(触发类型错误),否则返回两者的交叉类型:

type NoOverlap<T, U> = 
  keyof T & keyof U extends never 
    ? T & U 
    : never;

2. 锁定对象的字面量类型

默认TypeScript会把对象键推断为宽泛的string类型,需要用as const保留具体的键名和值类型,确保类型检测能精准识别重复键:

const A = {
  resetPassword: "/supplier/auth/reset-password",
  login: "/supplier/auth/login",
} as const;

const B = {
  selfInitiate: "/supplier/actions/request",
  getEmpanelmentReport: "/supplier/empanelment/report",
  getFormData: "/supplier/empanelment/form/",
  formSubmit: "/supplier/empanelment/submit/",
  login: "duplicate login"
} as const;

3. 创建带类型检测的合并函数

编写一个泛型函数mergeNoOverlap,在参数层面限制第二个对象不能与第一个对象有重复键,同时返回只读的合并结果:

function mergeNoOverlap<T, U>(
  a: T, 
  b: U extends NoOverlap<T, U> ? U : never
): Readonly<T & U> {
  return { ...a, ...b } as Readonly<T & U>;
}

4. 验证效果

调用该函数合并A和B时,因为存在重复的login键,TypeScript会立即抛出类型错误:

// 类型错误:"{ readonly selfInitiate: "/supplier/actions/request"; ... }" 无法赋值给类型 "never"
const C = mergeNoOverlap(A, B);

当移除B中的login键后,合并操作会正常通过,且返回的C是只读对象:

const B = {
  selfInitiate: "/supplier/actions/request",
  getEmpanelmentReport: "/supplier/empanelment/report",
  getFormData: "/supplier/empanelment/form/",
  formSubmit: "/supplier/empanelment/submit/",
} as const;

// 合并成功,C为只读的合并对象
const C = mergeNoOverlap(A, B);

可选:绑定目标类型SUPPLIER_ROUTE

如果需要确保合并结果严格符合SUPPLIER_ROUTE,可以在函数返回值上添加额外约束:

function mergeNoOverlap<T, U>(
  a: T, 
  b: U extends NoOverlap<T, U> ? U : never
): Readonly<T & U> extends SUPPLIER_ROUTE ? Readonly<T & U> : never {
  return { ...a, ...b } as Readonly<T & U>;
}

这样既会检测重复键,也能保证最终对象的结构与目标类型一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:53:15