LastIndexOf

Challenge

Implement the type version of Array.lastIndexOf, LastIndexOf<T, U> takes an Array T, any U and returns the index of the last U in Array T

For example:

type Res1 = LastIndexOf<[1, 2, 3, 2, 1], 2>; // 3
type Res2 = LastIndexOf<[0, 0, 0], 2>; // -1

Solution

Zur Lösung dieses Problems können wir mittels infer das jeweils erste Element aus der Tupel extrahieren und prüfen, ob es sich dabei um das gesuchte Element handelt. Bevor wir dies tun, sollten wir jedoch wieder einen Akkumulator definieren, um den aktuellen Index in Form einer Tupel zu erfassen (die Länge der Tupel ergibt den Index als Zahl). Zusätzlich benötigen wir einen Akkumulator für die letzte Position, an der U entdeckt wurde:

type LastIndexOf<
  T extends any[],
  U,
  CurrIdx extends number[] = [],
  LastIdx extends number[] = []
>

Nun rufen wir den Typ so lange rekursiv auf, bis wir alle Elemente durchlaufen haben. Wichtig ist dabei immer den aktuellen Index zu inkrementieren, indem wir ein neues Element in den Akkumulator einfügen. Ist H dabei das gesuchte Element, so setzen wir den neuen LastIdx, indem wir einfach den aktuellen Index zuweisen:

type LastIndexOf<
  T extends any[],
  U,
  CurrIdx extends number[] = [],
  LastIdx extends number[] = []
> = T extends [infer H, ...infer R]
  ? Equal<H, U> extends true
    ? LastIndexOf<R, U, [...CurrIdx, 1], [...CurrIdx]>
    : LastIndexOf<R, U, [...CurrIdx, 1], [...LastIdx]>
  : LastIdx["length"] extends 0
  ? -1
  : LastIdx["length"];

References