问题描述
我正在使用lodash merge
合并两个对象。 lodash(https://github.com/DefinitelyTyped/DefinitelyTyped/blob/bab9c9aef2477d222f014a25ce86585af76c3a5c/types/lodash/common/object.d.ts#L1718)的类型仅依赖于交集类型,而交集类型在数组方面存在一些缺点。
说我想合并这些类型的对象
interface One {
str: string;
arr: Array<{ foo: string }>;
}
interface Two {
num: number;
arr: Array<{ bar: string }>;
}
这些对象与lodash merge
合并后,其形状为
interface Merged {
str: string;
num: number;
arr: Array<{ foo: string; bar: string }>;
}
但这不是交叉点类型的工作方式(合理here)。对于arr
类型,您最终得到的是Array<{ foo: string; }> & Array<{ bar: string }>
,它具有以下问题:
declare const test: Array<{ foo: string }> & Array<{ bar: string }>;
test.forEach((item) => item.bar); // Property 'bar' does not exist on type '{ foo: string; }'.(2339)
是否可以为merge
定义一个更好的类型,以便对数组Array<A>
和Array<B>
获得Array<A & B>
而不是Array<A> & Array<B>
?它必须是某种递归映射类型,但我写它没有运气。
解决方法
我认为我们可以创建一种以递归方式标准化数组的类型。
type NomalizeArrays<T> = {
[P in keyof T]: T[P] extends any[] ? Array<NomalizeArrays<T[P][number]>> : NomalizeArrays<T[P]>
}
我们可以在T
的任何路口通过。除了数组,我们大部分都只保留结构。对于数组,我们采用T[P][number]
,它将是对象类型的交集。
似乎没有按预期工作,如果发现任何问题,请通知我:
let r = _.merge({
arr: [{ foo : "A"}],str: ""
},{
arr: [{ bar: "B"}],num: 1
})
r.arr.forEach(x => x.bar + x.foo);
let r2 = _.merge({
arr: [{ outerA: "",nested: [{ foo: "" }]}]
},{
arr: [{ outerB: "",nested: [{ bar: "" }]}]
})
r2.arr.forEach(x => {
x.outerA
x.outerB
x.nested.map(xx => xx.bar + xx.foo)
});