TypeScript与数组的交集

问题描述

我正在使用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)

Playground link

是否可以为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)
});

Playground Link