Unique

Challenge

Implement the type version of Lodash.uniq, Unique takes an Array T, returns the Array T without repeated values.

type Res = Unique<[1, 1, 2, 2, 3, 3]>; // expected to be [1, 2, 3]
type Res1 = Unique<[1, 2, 3, 4, 4, 5, 6, 7]>; // expected to be [1, 2, 3, 4, 5, 6, 7]
type Res2 = Unique<[1, "a", 2, "b", 2, "a"]>; // expected to be [1, "a", 2, "b"]
type Res3 = Unique<[string, number, 1, "a", 1, string, 2, "b", 2, number]>; // expected to be [string, number, 1, "a", 2, "b"]
type Res4 = Unique<[unknown, unknown, any, any, never, never]>; // expected to be [unknown, any, never]

Solution

Zur Lösung des Problems benötigen wir ein Hilfsargument in Form eines Akkumulators, um die gefunden, eindeutigen Elemente zwischenzuspeichern. Zusätzlich definieren wir einen Hilfstyp InArray, der eine Tupel sowie ein Element entgegennimmt und zurückgibt, ob sich das Element bereits in der Tupel befindet

type InArray<L, R extends any[]> = R extends [infer F, ...infer N]
  ? Equal<L, F> extends true
    ? true
    : InArray<L, N>
  : false;

Entsprechend können wir den finalen Typen so erweitern, dass jedes mittels infer extrahierte Element auf die Existenz im Akkumulator geprüft wird. Ist das Element noch nicht im Akkumulator enthalten, so können wir dieses ergänzen.

type Unique<T extends any[], Res extends any[] = []> = T extends [
  infer H,
  ...infer R
]
  ? InArray<H, Res> extends false
    ? Unique<R, [...Res, H]>
    : Unique<R, Res>
  : Res;

References