Intersection

Challenge

Implement the type version of Lodash.intersection with a little difference. Intersection takes an Array T containing several arrays or any type element including the union type, and returns a new union containing all intersection elements.

type Res = Intersection<[[1, 2], [2, 3], [2, 2]]>; // expected to be 2
type Res1 = Intersection<[[1, 2, 3], [2, 3, 4], [2, 2, 3]]>; // expected to be 2 | 3
type Res2 = Intersection<[[1, 2], [3, 4], [5, 6]]>; // expected to be never
type Res3 = Intersection<[[1, 2, 3], [2, 3, 4], 3]>; // expected to be 3
type Res4 = Intersection<[[1, 2, 3], 2 | 3 | 4, 2 | 3]>; // expected to be 2 | 3
type Res5 = Intersection<[[1, 2, 3], 2, 3]>; // expected to be never

Solution

Zur Lösung des Problems können wir einfach eine Schnittmenge aus allen Elementen der Tupeln bilden. Somit erhalten wir alle Elemente, die in allen Elementen enthalten sind, hierzu einige Beispiele:

2 | 3 &  1 | 2 => 2
3 &  1 | 2 | 3 => 3
3 &  1 | 2     => Nichts, da keinen uberschneidungen vorliegen.

Nun extrahieren wir einfach jedes Element der Tupel, und falls die Typvariable H eine Tupel ist, können wir mit dem Lookup typ [number] alle Elemente als Vereinigung erhalten. Sollte H bereits eine number oder Vereinigung sein, so müssen wir nichts machen, und vereinigen immer H mit den restlichen Elementen der Tupel:

type Intersection<T extends unknown[]> = T extends [infer H, ...infer R]
  ? H extends readonly any[]
    ? H[number] & Intersection<R>
    : H & Intersection<R>
  : number;

References