TypeScript:如何去除对象根键合并嵌套对象并转联合类型为交叉类型?
解决TypeScript合并多语言对象返回交叉类型的问题
你的merge函数当前返回的是各语言对象的联合类型,要改成返回交叉类型,可以通过自定义工具类型结合泛型调整来实现:
步骤1:定义联合转交叉的工具类型
TypeScript本身没有内置的联合转交叉类型,但可以利用条件类型的逆变特性实现:
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
步骤2:修改merge函数的泛型与返回类型
调整函数的泛型约束和返回类型,让它返回所有语言对象的交叉类型,同时修正内部的类型断言:
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; function merge<A extends Record<string, object>>(a: A): UnionToIntersection<A[keyof A]> { let ret = {} as UnionToIntersection<A[keyof A]>; // 注意:Object.keys的遍历顺序不固定,若需要默认语言优先,建议显式指定默认语言先合并 Object.values(a).forEach(obj => { ret = { ...ret, ...obj }; }); return ret; } const o = { en: { a: 1 }, de: { b: 2, c: "3" } }; const r = merge(o); // 此时 r 的类型为 {a: 1} & {b: 2, c: "3"}
补充说明
- 原函数中用
Object.keys遍历后取a[key],可以直接换成Object.values(a)更简洁。 - 实际场景中如果需要默认语言(比如
en)的属性覆盖其他语言的同名属性,建议先合并默认语言对象,再合并其他语言:function mergeWithDefault<A extends Record<string, object>, D extends keyof A>(a: A, defaultLang: D): UnionToIntersection<A[keyof A]> { let ret = { ...a[defaultLang] } as UnionToIntersection<A[keyof A]>; Object.entries(a).forEach(([lang, obj]) => { if (lang !== defaultLang) { ret = { ...ret, ...obj }; } }); return ret; }
内容的提问来源于stack exchange,提问作者danielmoessner
相关产品推荐
相关产品推荐

