网站搜索

Typescript 泛型遍历对象数组并求交集


假设有一个函数X,它可以接收任意数量的对象:

export function X<T extends object[]>(...classes: T): MergedClasses<T>;

我希望它返回该列表中每个对象的交集。例如,给定对象A、B、C和D,过程可能如下:

let X = A & B
X = X & C
X = X & D
// for any number of objects

然而,我想将其作为函数返回类型的一种类型来做(因此是 MergedClasses)

type MergedClasses<C extends object[]> = {
}

我知道可以做 [K for keyof C]: ,但从那之后我不确定如何组合这些对象,因为没有办法分配变量。

我查看了 Lodash 的 merge 类型定义,它只是一个重载函数,可以接收 1、2、3、4 或 5 个对象。所以它看起来好像可以合并任意数量的对象,但实际上它不能处理超过 5 个对象。

是否有可能动态合并这些对象,还是我必须像 Lodash 一样采取相同的方法?

答案#1

这里有一个使用递归定义的解决方案:

type IntersectionOf<A extends any[]> = A extends [infer T, ...infer R] ? T & IntersectionOf<R> : unknown

// type Test = {a: string} & {b: number} & {c: boolean}
type Test = IntersectionOf<[{a: string}, {b: number}, {c: boolean}]>

游乐场链接

这里有一个替代方案,使用来自此答案的 UnionToIntersection 帮助类型,虽然稍微复杂一些,如果第一个解决方案遇到编译器递归限制,这个方案可能更可取。然而,请注意,如果任何输入类型是联合类型,这种方法会产生不正确的行为,因为这些联合类型也会被转换为交叉类型。

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type IntersectionOf<A extends any[]> = UnionToIntersection<A[number]>

// type Test = {a: string} & {b: number} & {c: boolean}
type Test = IntersectionOf<[{a: string}, {b: number}, {c: boolean}]>

游乐场链接