Percentage Parser

Challenge

Implement PercentageParser. According to the /^(\+|\-)?(\d*)?(\%)?$/ regularity to match T and get three matches.

The structure should be: [plus or minus, number, unit] If it is not captured, the default is an empty string.

For example:

type PString1 = "";
type PString2 = "+85%";
type PString3 = "-85%";
type PString4 = "85%";
type PString5 = "85";

type R1 = PercentageParser<PString1>; // expected ['', '', '']
type R2 = PercentageParser<PString2>; // expected ["+", "85", "%"]
type R3 = PercentageParser<PString3>; // expected ["-", "85", "%"]
type R4 = PercentageParser<PString4>; // expected ["", "85", "%"]
type R5 = PercentageParser<PString5>; // expected ["", "85", ""]

Solution

Zur Lösung dieser Herausforderung hilft es, ein paar Hilfstypen zu definieren, um den finalen Typ zu vereinfachen und lesbarer zu gestalten:

// Alle Zahlen als Vereinigung
type Numbers = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
// Alle Operatoren
type Operator = "-" | "+";
// Alle Einheiten
type Unit = "%";

Nun laufen wir einfach wieder über alle Zeichen der Zeichenkette und prüfen, ob das jeweilige Zeichen nun eine Nummer, ein Operator oder eine Unit ist. Je nach Falls speichern wir das Zeichen in den Akkumulatoren Pre (Anfang), N (Alphabetische Zeichenkette), Post (Ende).

type PercentageParser<
  T extends string,
  Pre extends string = "",
  N extends string = "",
  Post extends string = ""
> = T extends `${infer H}${infer T}`
  ? H extends Numbers
    ? PercentageParser<T, Pre, `${N}${H}`, Post>
    : H extends Operator
    ? PercentageParser<T, `${H}`, N, Post>
    : H extends Unit
    ? PercentageParser<T, Pre, N, `${H}`>
    : never
  : [Pre, N, Post];

References

Inferring Within Conditional Types