Programmiersprache TypeScript 4.9 verbietet Gleichheitsprüfung mit Not a Number

Neben dem strikteren Umgang mit NaN bringt das Release den neuen Operator satisfies und verbessert den Umgang mit dem in-Operator.

In Pocket speichern vorlesen Druckansicht 7 Kommentare lesen
Schreibmaschine, Tastatur, Keyboard, Digitalisierung

(Bild: , gemeinfrei)

Lesezeit: 2 Min.
Inhaltsverzeichnis

Sieben Wochen nach der ersten Beta hat Microsoft das stabile Release von TypeScript 4.9 veröffentlicht. Das JavaScript-Superset führt den neuen Operator satisfies ein und verbietet Gleichheitsprüfungen mit NaN. Außerdem bietet der in-Operator deutlichere Typzuweisungen für den Schlüssel und das Objekt.

TypeScript 4.9 schafft mehr Klarheit im Umgang mit dem Spezialwert NaN, der für Not a Number, also keine Zahl steht. Für TypeScript, JavaScript und alle anderen Sprachen, die Gleitkommazahlen nach IEEE 754 implementieren legt die Spezifikation fest, dass Gleichheitschecks zu NaN grundsätzlich false ergeben.

Ein immer wieder auftauchender Fehler ist, mit != zu prüfen, ob ein Wert nicht NaN ist. Da jedoch auch NaN per Definition ebenso wie alle anderen Werte ungleich NaN ist, ist das Ergebnis immer true und der Vergleich sinnlos:

console.log(NaN == NaN)  // false
console.log(NaN != NaN)  // true

Daher verbietet TypeScript ab sofort Gleichheits- und Ungleichheitsprüfungen auf Not a Number und schlägt stattdessen den Einsatz der Methode Number.isNaN() vor:

function validate(someValue: number) {
    return someValue !== NaN;
    //     ~~~~~~~~~~~~~~~~~
    // error: This condition will always return 'true'.
    //        Did you mean '!Number.isNaN(someValue)'?
}

Der neue Operator satisfies prüft, ob ein Ausdruck einem bestimmten Typ entspricht, ohne den Typ des Ausdrucks zu ändern beziehungsweise über Typannotationen zuzuweisen. Folgendes zusammengefasste Beispiel aus dem TypeScript-Blog zeigt den Unterschied.

type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette1: Record<Colors, string | RGB> = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
};

const palette2 = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>;

// Fehler: (string | RGB)
const green1Normalized = palette1.green.toUpperCase();
// Korrekte Typinferrenz (string)
const green2Normalized = palette2.green.toUpperCase();

palette1 verwendet Typannotation, womit aber der Zugriff auf die Funktion toUpperCase nicht erlaubt ist. palette2 prüft dagegen nur die korrekten Typen, ohne einen Typ festzulegen.

Weitere Anwendungsbeispiele für satisfies, unter anderem zum Prüfen auf das Implementieren eines bestimmten Interfaces lassen sich dem zugehörigen Issue auf GitHub entnehmen.

Im Zusammenspiel mit dem JavaScript-Operator in setzt TypeScript 4.9 auf ein weniger striktes Type Narrowing als bisher. Folgendes Codebeispiel aus dem TypeScript-Blog führte bisher zu einem Fehler, da TypeScript packageJSON als object zugeordnet hat, das die Property name nicht enthält:

interface Context {
  packageJSON: unknown;
}

function tryGetPackageName(context: Context) {
  const packageJSON = context.packageJSON;
  // Check to see if we have an object.
  if (packageJSON && typeof packageJSON === "object") {
    // Check to see if it has a string name property.
    if ("name" in packageJSON && 
        typeof packageJSON.name === "string") {
    //                     ~~~~
    // error! Property 'name' does not exist on type 'object.
      return packageJSON.name;
    //                   ~~~~
    // error! Property 'name' does not exist on type 'object.
    }
  }

  return undefined;
}

Mit dem aktuellen Release stellt TypeScript für den Ausdruck key in obj für existierende Schlüssel sicher, dass der Wert für key entweder ein String, eine Zahl oder ein Symbol sein muss (string | number | symbol) und obj vom Typ object ist. Damit funktioniert obiges Codebeispiel fehlerfrei.

Weitere Neuerungen in TypeScript 4.9 sowie Informationen zu ein paar kleineren Performance-Verbesserungen lassen sich dem TypeSript-Blog entnehmen.

(rme)