const a = document.getElementById("a")
if (a instanceof HTMLInputElement) {
// a.value is valid here
console.log(a.value)
}
Ein sicherer Weg
Der obige Codeschnipsel ist die Quintessenz der Antwort; lesen Sie weiter, um die Gründe zu erfahren.
Die meisten vorhandenen Antworten empfehlen Typ-Assertionen (type casts), die die Aufgabe erfüllen, aber ein bisschen so sind wie die Verwendung von any
-was die Typüberprüfung deaktiviert. Es gibt einen besseren, sichereren Weg.
Mit Type Assertions wird TypeScript angewiesen, so zu tun, als ob eine Variable den von uns angegebenen Typ hätte. Als solches führt TypeScript eine Typüberprüfung durch für diesen Typ . Wenn wir einen Fehler gemacht und den falschen Typ angegeben haben, werden wir ein falsches Gefühl der Sicherheit bekommen, da es keine Kompilierungswarnungen geben wird, aber es werden Fehler zur Laufzeit auftreten. Schauen wir uns ein Beispiel an:
// <input id="a" value="1">
// <div id="b" value="2"></div>
const a = document.getElementById("a") as HTMLInputElement
const b = document.getElementById("b") as HTMLInputElement
console.log(a.value) // 1
console.log(b.value) // undefined
Wir haben TypeScript gesagt, dass a
y b
sind vom Typ HTMLInputElement und werden als solche behandelt. Da jedoch b
ist vom Typ HTMLDivElement, der nicht die Eigenschaft value
Eigentum, b.value
gibt zurück. undefined
.
Typenverengung mit Typenschützern
Ein besserer Weg ist die Verwendung von Type Guards, die eine bessere Kontrolle ermöglichen.
A Typschutz ist eine Möglichkeit, den Typ einer Variablen zur Laufzeit zu bestimmen. Während Typ-Assertions einfach sagen: "Variable x ist vom Typ T", sagen Typgarantien: "Die Variable x ist vom Typ T, wenn sie diese Eigenschaften hat". Schauen wir uns kurz an, wie ein Type Guard aussieht:
const a = document.getElementById("a")
if (a instanceof HTMLInputElement) {
// a == input element
} else {
// a != input element
}
Dieser Typ Guard prüft einfach, ob a
ist eine Instanz von HTMLInputElement. Wenn es das ist, erkennt TypeScript das und behandelt a
innerhalb des if-Blocks als von diesem Typ - es wird den Zugriff auf alle Eigenschaften des Eingabeelements ermöglichen. Dies wird als "type narrowing" bezeichnet.
Warum sollten Sie Type Guards statt Type Assertions verwenden? Aus demselben Grund, aus dem Sie Fehler behandeln. Typ-Guards geben zwar immer noch keine Warnungen zur Kompilierzeit aus, aber sie geben Ihnen die Kontrolle. Sie (und TypeScript) können nicht garantieren, ob die value
Eigenschaft vorhanden ist, aber mit Typ-Assertions können Sie entscheiden, was zu tun ist, wenn dies nicht der Fall ist. Type Assertions sind wie das Ignorieren von Fehlern und Type Guards sind wie deren Behandlung.
Verwendung von Typensicherungen
Wir werden drei Möglichkeiten zeigen, wie der Fehler "Die Eigenschaft existiert nicht" behoben werden kann. In jedem Beispiel wird derselbe HTML-Code verwendet, aber er ist in jedem Beispiel separat enthalten, damit es leichter zu lesen ist.
-
Typ-Assertionen
// <input id="a" value="1">
// <div id="b" value="2">
const a = document.getElementById("a") as HTMLInputElement // correct type assertion
const b = document.getElementById("b") as HTMLInputElement // incorrect type assertion
const c = document.getElementById("c") as HTMLInputElement // element doesn't exist
console.log(a.value) // 1
console.log(b.value) // undefined
console.log(c.value) // Uncaught TypeError: Cannot read property 'value' of null
-
Inline-Typ Schutzvorrichtungen
// <input id="a" value="1">
// <div id="b" value="2">
const a = document.getElementById("a")
const b = document.getElementById("b")
const c = document.getElementById("c")
if (a instanceof HTMLInputElement) {
console.log(a.value) // 1
}
if (b instanceof HTMLInputElement) {
console.log(b.value)
}
if (c instanceof HTMLInputElement) {
console.log(c.value)
}
b
y c
haben nichts protokolliert, da es sich nicht um Eingabeelemente handelt. Beachten Sie, dass kein unerwartetes Verhalten wie in den Beispielen für "type assertions" auftrat.
Beachten Sie, dass dies ein erfundenes Beispiel ist. Normalerweise würden Sie die Fälle behandeln, in denen die Typen nicht die erwarteten sind. Ich werfe oft, wenn ein Typ nicht übereinstimmt, wie so:
if (!(b instanceof HTMLInputElement)) {
throw new Error("b is not an input element")
}
// b == input element (for the rest of this block)
- Funktionstyp Schutzvorrichtungen
Dieses Beispiel ist etwas fortgeschrittener und für diesen Anwendungsfall unnötig. Es zeigt jedoch Funktionstypgarantien und eine "flexiblere" Typgarantie.
Funktionstyp-Guards sind Funktionen, die feststellen, ob der angegebene Wert von einem bestimmten Typ ist. Sie tun dies, indem sie einfach ein bool zurückgeben. Damit TypeScript erkennt, dass es sich um einen Type Guard handelt, müssen Sie ein Type-Prädikat verwenden (siehe Kommentar im Beispiel unten).
// <input id="a" value="1">
// <div id="b" value="2">
const a = document.getElementById("a")
const b = document.getElementById("b")
const c = document.getElementById("c")
if (hasValueProperty(a)) {
console.log(a.value) // 1
}
if (hasValueProperty(b)) {
console.log(b.value)
}
if (hasValueProperty(c)) {
console.log(c.value)
}
const d = {
"value": "d",
}
if (hasValueProperty(d)) {
console.log(d.value) // d
}
type WithValue = {
value: string
}
// hasValueProperty is a type guard function the determines whether x is of type
// WithValue.
//
// "x is WithValue" is a type predicate that tells TypeScript that this is a
// type guard.
function hasValueProperty(x: unknown): x is WithValue {
return typeof x === "object" && x !== null && typeof (x as WithValue).value === "string"
}
Da unsere Typüberwachung nur das Vorhandensein der Eigenschaft "value" prüft, kann sie auch für jedes andere Objekt (nicht nur für Elemente) verwendet werden.