It’s #FrontendFriday – Type predicates in TypeScript

11.02.2022

In diesem #FrontendFriday geht es um ein Feature in TypeScript mit dessen Hilfe euer Code noch typsicherer wird: Type predicates.

Was sind Type predicates?

Type predicates sind ähnlich wie Type Guards. Ein Type Guard ist eine Expression die eine Laufzeitprüfung durchführt und im aktuellen Scope für einen bestimmten Type garantiert. Type predicates arbeiten dagegen in Funktionen. Wenn ein Parameter jedoch verschiedene Typen haben kann, kann mit Type predicates dieser Type eingegrenzt werden.

Ein Parameter kann verschiedene Typen haben?

Wer mit TypeScript nicht so vertraut ist, wird sich dich Frage stellen, wie ein Parameter verschiedene Typen haben kann. In TypeScript ist es durch „Union-Types“ möglich, mehrere Typen für einen einzelnen Wert zu deklarieren. Ein einfaches Beispiel könnte so aussehen:

// mySuperCoolVariable kann jetzt vom Type 'number', 'string' oder 'null' sein
let mySuperCoolVariable: number | string | null = ....

//animal kann jetzt 'Fish', 'Bird' oder 'Dog' sein
let animal: Fish | Bird | Dog = ....

Um Laufzeitfehler zu vermeiden, müssen wir es ermöglichen, Union-Types auf den tatsächlichen Typ des aktuellen Werts einzugrenzen.

Kann ich das nicht auch mit ‚instanceof‘ lösen?

Wenn man das Keyword instanceof des TypeGuard kennt, fragt man sich vielleicht wofür man Type predicates benötigt. Bei instanceof wird geprüft, ob ein Parameter einem bestimmten Typ entspricht. Anhand dessen wird dann ein true/false geliefert. Neben true/false kann man mit Type predicates spezielle Return Types definieren, um dem Compiler zu signalisieren, mit welchem speziellen Wert gearbeitet wird.

Anhand des folgenden Beispiels wenden wir die Type predicates an und können dadurch eingrenzen, um welche Art (Type) von Tier es sich handelt.

interface Fish {
  canSwim: boolean;
}
interface Bird {
  canFly: boolean;
}

function isFish(animal: Fish | Bird): animal is Fish{
  return (animal as Fish).canSwim !== undefined;
}

if (isFish(animal)) {
  console.log(animal.canSwim);
  // Do what only a Fish can do
} else {
  console.log(animal.canFly);
  // Do what only a Bird can do
}

Der Returnwert der isFish() Funktion ist in diesem Fall nicht true/false sondern vom Typ Fish. Ohne Type predicates würde der Compiler bei console.log(animal.canSwim); und console.log(animal.canFly); beanstanden, dass unklar ist, um welchen Typ animal es sich handelt und das jeweilige Property ggf. nicht vorhanden ist.

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*