Chunk

Challenge

Do you know lodash? Chunk is a very useful function in it, now let’s implement it. Chunk<T, N> accepts two required type parameters, the T must be a tuple, and the N must be an integer >=1

type exp1 = Chunk<[1, 2, 3], 2>; // expected to be [[1, 2], [3]]
type exp2 = Chunk<[1, 2, 3], 4>; // expected to be [[1, 2, 3]]
type exp3 = Chunk<[1, 2, 3], 1>; // expected to be [[1], [2], [3]]

Solution

Zur Lösung dieses Problems benötigen wir zwei weitere Hilfsargumente in Form von Akkumulatoren. Zum einen müssen wir immer eine Tupel so lange mit Elementen befüllen, bis diese die Länge des Chunks entspricht (wird im Typ als Partition bezeichnet). Außerdem brauchen wir einen Tupel, die alle anderen Chunkssammelt und die wir als Ergebnis zurückgeben können (Acc).

type Chunk<
  T extends any[],
  Size extends number,
  Acc extends any[] = [],
  Partition extends any[] = []
>

Nun füllen wir das Typargument Partition solange mit Elementen, bis dieses die Länge von Size entspricht. Ist dies der Fall, so packen wir Partition in den finalen Akkumulator Acc, und setzen Partition wieder auf eine leere Tupel zurück. Dies wird so lange wiederholt, bis wir die ganze Tupel T durchlaufen und alle Elemente in Chunks untergliedert haben.

type Chunk<
  T extends any[],
  Size extends number,
  Acc extends any[] = [],
  Partition extends any[] = []
> = T extends [infer H, ...infer R]
  ? Partition["length"] extends Size
    ? // Ist die Partition voll, so wird diese dem Akkumulator hinzugefuegt, und das aktuelle Element wird erneut durchlaufen.
      Chunk<[H, ...R], Size, [...Acc, Partition], []>
    : // Ansonsten wird jedes Element in die aktuelle Partition gepackt.
      Chunk<[...R], Size, Acc, [...Partition, H]>
  : // Befinden sich zum Schluss noch Element in der Partition, so werden diese in den Akkumulator gepackt.
  Partition["length"] extends 0
  ? [...Acc]
  : [...Acc, Partition];

References