如何将指定答案转为不使用'any'类型的TypeScript深合并函数
无
any类型的TypeScript深度合并实现 原代码的问题在于使用object类型导致类型信息丢失,且无法正确推导嵌套对象的合并类型。以下是改进后的实现,全程未使用any:
类型定义与工具函数
首先定义递归合并类型,用于推导合并后的对象结构:
// 递归合并两个对象的类型,保留嵌套结构 type MergeDeep<T, U> = T extends object ? U extends object ? { [K in keyof T | keyof U]: K extends keyof U ? K extends keyof T ? MergeDeep<T[K], U[K]> : U[K] : T[K] } : U : U; // 带类型谓词的对象判断函数,让TS能识别判断后的类型 export function isObject(item: unknown): item is Record<string, unknown> { return !!item && typeof item === "object" && !Array.isArray(item); }
深度合并函数实现
通过泛型和函数重载,确保类型安全且返回类型精确:
// 函数重载:支持单个源对象 export function mergeDeep<T extends object, U extends object>(target: T, source: U): MergeDeep<T, U>; // 函数重载:支持多个源对象 export function mergeDeep<T extends object, U extends object[]>(target: T, ...sources: U): MergeDeep<T, U[number]>; // 核心实现 export function mergeDeep(target: object, ...sources: object[]): object { if (!sources.length) return target; const source = sources.shift(); if (isObject(target) && isObject(source)) { for (const key in source) { const sourceValue = source[key]; if (isObject(sourceValue)) { // 若目标对象当前key不存在或不是对象,先初始化空对象 if (!isObject(target[key])) { Object.assign(target, { [key]: {} }); } // 递归合并嵌套对象 mergeDeep(target[key] as object, sourceValue); } else { // 非对象类型直接覆盖 Object.assign(target, { [key]: sourceValue }); } } } return mergeDeep(target, ...sources); }
测试代码
const obj1 = { one: { two: { keep: "yes!", change: "should not see me", }, three: { four: { keep: "yes!", change: "should not see me", }, }, }, }; const obj2 = { one: { two: { change: "NICE 1!!", }, three: { four: { change: "NICE 2!!", }, }, }, }; // 此时mergeDeep的返回类型会被正确推导为合并后的结构 const result = mergeDeep(obj1, obj2); console.log(JSON.stringify(result, null, 2));
关键改进点
- 类型谓词:
isObject函数添加类型断言,让TypeScript能在条件判断后识别对象类型,避免类型模糊 - 递归泛型:
MergeDeep类型递归处理嵌套对象,确保合并后的返回类型与实际结构一致 - 函数重载:针对单个/多个源对象的场景分别定义重载,让调用时的类型推导更精准
- 类型安全:全程使用
unknown和泛型替代any,避免类型逃逸
内容的提问来源于stack exchange,提问作者Paulo Fernando
相关产品推荐
相关产品推荐

