Fill

Challenge

Fill, a common JavaScript function, now let us implement it with types. Fill<T, N, Start?, End?>, as you can see,Fill accepts four types of parameters, of which T and N are required parameters, and Start and End are optional parameters. The requirements for these parameters are: T must be a tuple, N can be any type of value, Start and End must be integers greater than or equal to 0.

type exp = Fill<[1, 2, 3], 0>; // expected to be [0, 0, 0]

In order to simulate the real function, the test may contain some boundary conditions, I hope you can enjoy it :)

Solution

Zur Lösung dieses Problems benötigen wir zwei Hilfsargumente. Das erste Hilfsargument ist ein Akkumulator, der die aktuelle Position (oder Index) in der Tupel erfasst. Zusätzlich wird ein Hilfsargument als Flag benötigt, damit wir in jedem Aufruf des Typs wissen, ob wir nun über den Startindex hinaus sind und nun Element austauschen dürfen.

type Fill<
  T extends unknown[],
  N,
  // Start und End sind optional, daher vergeben wir einen Standard-Wert
  Start extends number = 0,
  End extends number = T["length"],
  // Akkumulator, der den aktuellen Index in Form der Laenge der Tupel darstellt
  L extends 1[] = [],
  // Flag, die angibt, ob wir nun Elemente austauschen koennen
  IsReplace extends boolean = false
>

Jetzt laufen wir mittels infer über jedes Element der Tupel, und sobald wir im “Replace”-Modus sind, tauschen wir die Elemente aus. Hiernach rufen wir den Typ mit den restlichen Elementen erneut auf, bis wir die Tupel durchlaufen haben

type Fill<
  T extends unknown[],
  N,
  // Start und End sind optional, daher vergeben wir einen Standard-Wert
  Start extends number = 0,
  End extends number = T["length"],
  L extends 1[] = [],
  IsReplace extends boolean = false
> = Start extends End
  ? T
  : T extends [infer Head, ...infer Rest]
  ? L["length"] extends Start
    ? // Wir setzen die Flag 'IsReplace' auf true, sodass im nachesten Aufruf ein Auftauschen der Elemente stattfindet
      [N, ...Fill<Rest, N, Start, End, [1, ...L], true>]
    : L["length"] extends End
    ? [Head, ...Fill<Rest, N, Start, End, [1, ...L], false>]
    : [
        IsReplace extends true ? N : Head,
        ...Fill<Rest, N, Start, End, [1, ...L], IsReplace>
      ]
  : [];

References