In JavaScript:

function doSomething(mybar) {
  if (!(mybar instanceof Bar)) throw new TypeError("mybar");
  // ...other guard clauses
}

In TypeScript:

function doSomething(mybar: Bar) {
  // is guard clause ALWAYS redundant?
  // ...other guard clauses
}

Ich validiere Eingaben gerne mit Schutzklauseln. In JavaScript würde ich also testen, ob mybar eine Instanz von Bar ist, und wenn dies nicht der Fall ist, würde ich ein TypeError werfen.

Ist mybar in TypeScript garantiert der richtige Typ? (Und damit die Notwendigkeit dieser ersten Schutzklausel beseitigen)


AKTUALISIEREN

Im Folgenden finden Sie einige gute Antworten, die von "es ist definitiv möglich" über "es könnte passieren" bis zu "es kann nicht passieren" reichen.

Ein guter Weg, um die Frage zu formulieren, ist vielleicht: Wenn es möglich ist, dass zur Laufzeit der falsche Typ angegeben wird, nach welchem Mechanismus würde dies geschehen? Ein Fehler beim Typecasting zum Beispiel?

4
lonix 19 Jän. 2019 im 14:11

4 Antworten

Beste Antwort

instanceof ist ein Test, wenn das Objekt eine Instanz von Bar ist. Während dies bedeutet, dass der Typ des Parameters auch Bar ist, ist das Gegenteil nicht unbedingt der Fall. Typescript verwendet die strukturelle Typisierung, sodass jedes Objekt mit der Struktur Bar mit dem Funktionsparameter kompatibel ist. Dieser Code ist also vollkommen gültig:

class Bar {
    bar: number;
}
function doSomething(p: Bar) { }
doSomething({
    bar: 10
})

Wenn Sie private Eigenschaften haben, können Sie das Objekt nicht so einfach "fälschen", aber selbst dann können wir immer any behaupten:

class Bar {
    private bar: number;
}
function doSomething(p: Bar) { }
doSomething({ // error now
    bar: 10
})
doSomething({ // breaking out of type safety
    bar: 10
} as any)

Und wenn Ihre Codebasis nicht vollständig TS ist, geht jede Art von Sicherheit aus dem Fenster. JS kann Ihre TS-Funktion nach Belieben aufrufen.

Bedeutet dies, dass Sie immer den Scheck einschließen sollten? Ich würde dagegen argumentieren. JS ist mit seinen Typen ziemlich locker (und TS auch), und das erwarten Ihre Benutzer. Wenn es wie eine Ente quakt, ist es eine Ente, lautet das alte JS-Mantra. Wenn das Objekt die Eigenschaften hat, mit Ihrer Funktion zu arbeiten, sollte es mit Ihrer Funktion funktionieren, unabhängig davon, wie es erstellt wurde.

2
Titian Cernicova-Dragomir 19 Jän. 2019 im 11:47

Das hängt von Ihrer Funktion ab. Wenn es sich um eine private Funktion handelt, auf die nur Sie Zugriff haben, kann TS sicherstellen, dass beim Kompilieren immer der richtige Typ vorhanden ist. Wenn es sich um eine öffentliche Funktion handelt, die von einem anderen Benutzer / einer anderen Partei verwendet werden soll, ist eine Überprüfung erforderlich, wenn Sie eine gewisse Ausfallsicherheit wünschen.

Beim TS-Typ geht es um das Entwerfen Ihrer Software. Unabhängig davon, wie gut Sie sie entwerfen, wenn der Benutzer sie falsch hält, bricht sie. Stellen Sie also nur wenige öffentliche Plätze frei und stellen Sie dort Schecks auf.

2
bigopon 19 Jän. 2019 im 12:06

So beantworten Sie Ihre aktualisierte Frage:

Wenn es möglich ist, dass zur Laufzeit der falsche Typ angegeben wird, nach welchem Mechanismus würde dies geschehen? Ein Fehler beim Typecasting zum Beispiel?

Es gibt einige Möglichkeiten, wie dies passieren kann:

  • doSomething wurde aus einer JavaScript-Datei aufgerufen (ohne checkJs oder @ts-check)
  • Ein Objekt ähnlich Bar wird bereitgestellt. Es ist strukturell dasselbe, aber es ist keine Instanz von Bar.
  • Ein falsches Argument wurde von einem anderen Entwickler in Bar umgewandelt
  • Ein Argument vom falschen Typ wurde automatisch in any umgewandelt (fehlende Typdefinitionen, Typinferenz geht verloren)
  • Ein Argument vom falschen Typ wurde von einem schlecht geschriebenen Typschutz als Bar bestätigt
  • Ein Argument vom falschen Typ wurde als Bar behandelt, da seine Definition an einer anderen Stelle in Ihrem Projekt erweitert wurde
  • Ihr Code wurde in einer Umgebung versendet und verbraucht, in der keine Build-Pipeline vorhanden ist. Daher können keine Fehler zur Kompilierungszeit vorliegen (z. B. als UMD-Paket verteilt).
  • Ein Objekt oder Array wurde mit einem nicht vorhandenen Schlüssel indexiert (TypeScript geht davon aus, dass es niemals undefined sein kann).
  • Ein fragwürdig typisierter Teil der Standardbibliothek wird in der Mischung verwendet (zum Beispiel wird Promise.resolve.call(1) die Laufzeit erhöhen, obwohl TypeScript dies akzeptiert).
2
Karol Majewski 9 März 2019 im 21:19

In TypeScript funktionieren die Dinge anders als in JavaScript. Wenn Sie in TypeScript Argumente eines anderen Typs als der in der Funktionssignatur angegebenen übergeben, wird beim Kompilieren ein Fehler angezeigt, und Sie müssen daher den genauen Typ der Funktionsargumente befolgen.

1
Manu Bhardwaj 19 Jän. 2019 im 11:16