Typoskript-Vorlagen-String-Typen als Diskriminanten

Verbesserte Vorlagenliteraltypen mit Typescript 4.5

Was ist "Einengung" in TS?

Bevor wir einen Blick auf die Erweiterung von Literaltypen in Typescript 4.5 und höher werfen, möchte ich kurz noch einmal zusammenfassen, was „Einengung“ in diesem Zusammenhang eigentlich bedeutet. Grundsätzlich können Sie einen Typ in Typescript eingrenzen, indem Sie die Eigenschaften der Entität überprüfen. Existiert auf der Entität eine Eigenschaft, die nur für einen bestimmten Typ verfügbar ist, dann versteht Typescript dies und kann daher die richtigen Typen bereitstellen.

Das folgende Codebeispiel zeigt, was ich damit meine.

type Addition = {
    sum: number;
}

type Subtraction = {
    result: number;
}

function calculate(action: Addition | Subtraction) {
    if ('sum' in action) {
      // Simple example of using properties
      // of an entity to narrow down its
      // actual type.
      //
      // 'action' is at this point of type
      // 'Addition'. Nice!
      const addition = action;
    }
}

Eingrenzen für Vorlagen-String-Typen

Ab Typescript Version 4.5 kann dieses Muster auch auf Vorlagenliteraltypen angewendet werden, die auch als spezielle Zeichenfolgen mit Backticks bezeichnet werden. Der Mustervergleich wird in der Sprache wirklich mächtig.

Damit die Eingrenzung nutzbar wird, müssen natürlich alle Typen im Vergleich denselben Eigenschaftsschlüssel haben. Ansonsten können Sie einfach die übliche Verengung wie oben verwenden.

Das folgende Codebeispiel zeigt, wie Vorlagenzeichenfolgen die Einengung verwenden können:

type Addition = {
    variant: `${string}-addition`;
    sum: number;
}

type Subtraction = {
    variant: `${string}-subtraction`;
    result: number;
}

function process(action: Addition | Subtraction) {
    if (action.variant === "simple-addition") {
        // Stupid simple example, but you get the idea:
        // We used 'simple-addition', and the pattern 
        // matching by TS understood that '...-addition'
        // can be discriminated to 'Addition'.
        const addition = action;
    }
}
//
// Example that DOES NOT work.
//
// This demo illustrates that the
// discriminante has to be a string,
// else the pattern matching worn't work.

type Addition = {
    variant: `${string}-arithemtic`;
    sum: number;
}

type Subtraction = {
    variant: `${number}-arithemtic`;
    result: number;
}

function process(action: Addition | Subtraction) {
    if (action.variant === "123-arithemtic") {
        // Still 'Addion | Subtraction',
        // as we can only compare against
        // a string '123-arithmetic', which
        // is of course the same for both.
        const addition = action;
    }
}

Und jetzt wissen Sie, wie man Vorlagenliterale in Typescript einschränkt! Dies mag eine Funktion sein, die Sie nicht sehr oft verwenden werden, aber wenn es angebracht ist, kann sie meiner Meinung nach die Codekomplexität erheblich reduzieren und Ihre Codebasis ein wenig sauberer halten als ohne die Funktion.