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.
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.
Keine Zahl kennt keine Gleichheit
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)'?
}
Voraussetzung erfüllt, Typ erhalten
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.
Klarere Typen für in
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)