Warum erzeugt der &&-Operator den Typ des zweiten Operanden?
-
12-12-2019 - |
Frage
Die TypeScript-Spezifikation gibt in §4.15.6 darüber Auskunft &&
Operator:
Der &&-Operator lässt zu, dass die Operanden jeden Typs haben und erzeugt einen Ergebnis vom gleichen Typ wie der zweite Operand.
In Javascript ist das &&
Der Operator gibt den ersten Operanden zurück, wenn er falsch ist, andernfalls gibt er den zweiten Operanden zurück (siehe ECMA-262 §11.11).
Das heißt, wenn der linke Operand falsch ist, &&
gibt einen Wert zurück, der dem Typ des linken Operanden entspricht.Zum Beispiel,
typeof ( false && {} ) === "boolean" // true
typeof ( '' && 1 ) === "string" // true
typeof ( null && "hello" ) === "object" // true
typeof ( NaN && true ) === "number" // true
Typoskript würde gemäß der oben zitierten Regel falsch Sagen Sie die Typen der oben genannten Ausdrücke voraus Object
, Number
, String
Und Boolean
, jeweils.
Vermisse ich etwas?Gibt es einen guten Grund, den Typ eines zu erstellen? &&
Stimmt der Ausdruck mit dem Typ des zweiten Operanden überein?Sollte sich der Ergebnistyp nicht wie der verhalten ||
Operator und gibt den besten gemeinsamen Typ der beiden Operanden zurück und Any
wenn es keinen besten gemeinsamen Typ gibt?
Lösung
Um es kurz zu machen: Es gibt hier keine Lösung, die allen gefällt.
Betrachten Sie diese gängige Redewendung:
var customer = GetCustomer(...); // of type 'Customer'
var address = customer && customer.address;
if(address) {
printAddressLabel(address); // Signature: (Address) => void
} else {
// Couldn't find the customer or the customer has no address on file
}
Es wäre ziemlich lahm, aufzugeben und zu entscheiden, dass „Adresse“ „beliebig“ ist, da es keinen optimalen gemeinsamen Typ zwischen „Kunde“ und „Adresse“ gibt.
In den meisten Fällen, in denen der &&-Operator verwendet wird, handelt es sich um beide Typen bereits übereinstimmen, oder && wird in einer wertzusammenführenden Weise wie oben verwendet.In beiden Fällen erhält der Benutzer durch die Rückgabe des Typs des rechten Operanden den erwarteten Typ.
Auch wenn die Typsicherheit zu diesem Zeitpunkt technisch nicht mehr funktioniert, geschieht dies nicht in einer Weise, die wahrscheinlich zu einem Fehler führt.Entweder testen Sie den resultierenden Wert auf Wahrheitsgehalt (in diesem Fall ist der Typ mehr oder weniger irrelevant), oder Sie verwenden den mutmaßlich richtigen Operanden für eine Operation (im Beispiel oben wird beides durchgeführt).
Wenn wir uns die von Ihnen aufgeführten Beispiele ansehen und so tun, als sei der linke Operand unbestimmt wahr oder falsch, und dann versuchen, vernünftigen Code zu schreiben, der mit dem Rückgabewert operiert, wird es viel klarer – es gibt einfach nicht viel, was Sie tun können Tun mit „false && {}“ geht das noch nicht in eine „beliebige“ Argumentposition oder einen Wahrheitstest.
Nachtrag
Da einige Leute von dem oben Gesagten nicht überzeugt waren, hier eine andere Erklärung.
Stellen wir uns für einen Moment vor, dass das TypeScript-Typsystem drei neue Typen hinzugefügt hat: Truthy<T>
, Falsy<T>
, Und Maybe<T>
, die mögliche wahrheitsgemäße/falsche Werte des Typs darstellen T
.Die Regeln für diese Typen lauten wie folgt:
Truthy<T>
verhält sich genau soT
- Sie können auf keine Eigenschaften von zugreifen
Falsy<T>
- Ein Ausdruck des Typs
Maybe<T>
, wenn es als Bedingung in einem verwendet wirdif
Block, wird zu einemTruthy<T>
im Körper desselbenif
Block und aFalsy<T>
imelse
Block
Damit könnten Sie Dinge wie diese tun:
function fn(x: Maybe<Customer>) {
if(x) {
console.log(x.address); // OK
} else {
console.log(x.phone); // Error: x is definitely falsy
}
console.log(x.name); // Warning: x might be falsy!
}
Bisher ziemlich gut.Jetzt können wir herausfinden, welche Typregeln für den &&-Operator gelten.
Truthy<T> && x
sollte ein Fehler sein – wenn bekannt ist, dass die linke Seite wahr ist, hätten Sie einfach schreiben sollenx
Falsy<T> && x
sollte ein Fehler sein - wenn bekannt ist, dass die linke Seite falsch ist,x
ist nicht erreichbarer CodeMaybe<T> && x
sollte produzieren...Was?
Wir kennen das Ergebnis Maybe<T> && x
wird entweder ein falscher Wert vom Typ sein T
, oder x
.Es kann nicht produzieren Truthy<T>
(es sei denn T
== die Art von x
in diesem Fall ist die gesamte Diskussion hinfällig).Nennen wir diesen neuen Typ Falsy<T> XOR Maybe<U>
.
Was sollen die Regeln sein? Falsy<T> XOR Maybe<U>
Sei?
- Offensichtlich können Sie keine Eigenschaften von verwenden
T
drauf.Wenn der Wert vom Typ istT
, es ist falsch und nicht sicher in der Anwendung. - Sie sollten es als verwenden können
Maybe<U>
, seitFalsy<T>
UndFalsy<U>
haben die gleichen Verhaltensweisen - Sie sollten keine Eigenschaften von verwenden können
U
, da der Wert möglicherweise immer noch falsch ist. - Wenn Sie es in einem verwenden
if
testen, dann sollte es ein werdenTruthy<U>
im Block davonif
Stellungnahme
Mit anderen Worten, Falsy<T> XOR Maybe<U>
Ist Maybe<U>
.Es folgt allen den gleichen Regeln.Sie müssen das Typsystem hier überhaupt nicht komplizieren, indem Sie dieses Seltsame hinzufügen XOR
Typ, da es bereits einen Typ gibt, der alle von Ihnen benötigten Spezifikationen erfüllt.
Das ist ein bisschen so, als würde man jemandem eine Kiste geben und sagen: „Das ist entweder eine leere Kiste mit Müll oder eine volle Kiste mit Wertstoffen.“Den Inhalt der Box können Sie bedenkenlos in die Recyclingtonne entleeren.