printf

Challenge

Implement Format<T extends string> generic.

For example,

type FormatCase1 = Format<"%sabc">; // FormatCase1 : string => string
type FormatCase2 = Format<"%s%dabc">; // FormatCase2 : string => number => string
type FormatCase3 = Format<"sdabc">; // FormatCase3 :  string
type FormatCase4 = Format<"sd%abc">; // FormatCase4 :  string

Solution

/*
Wandelt die Platzhalter wie %s oder %d in einen Array aus Typen um ([string, number])
z.B. `xxx%sxxx%d' : [string, number]
*/
type ArrayOfPlaceholders<
T extends string,
Acc extends any[] = []

> = T extends `${infer H}%${infer Char}${infer Rest}`
> ? Char extends "d" | "s"

    ? Char extends "d"
      ? ArrayOfPlaceholders<Rest, [...Acc, number]>
      : ArrayOfPlaceholders<Rest, [...Acc, string]>
    : ArrayOfPlaceholders<Rest, Acc>

: Acc;

/*
Nimmt eine Tupel entgegen und erzeugt eine Reihe von Funktionsaufrufen, die am Ende immer einen `string` zurueckgeben.
Eingabe: [string, number]
Ausgabe: (arg: string) => (arg:number) => string
*/
type ArrayToChainedCalls<T extends any[]> = T extends [infer H, ...infer Rest]
? (arg: H) => ArrayToChainedCalls<Rest>
: string;

type Format<T extends string> = ArrayToChainedCalls<ArrayOfPlaceholders<T>>;

References