Aufruf Konstruktor auf Typoskript-Klasse, ohne neue
In JavaScript, kann ich definieren Sie einen Konstruktor-Funktion, die aufgerufen werden können, mit oder ohne new
:
function MyClass(val) {
if (!(this instanceof MyClass)) {
return new MyClass(val);
}
this.val = val;
}
Kann ich dann konstruieren MyClass
Objekte mithilfe der folgenden Anweisungen:
var a = new MyClass(5);
var b = MyClass(5);
Ich habe versucht, ein ähnliches Ergebnis erzielen mit dem Typoskript-Klasse unten:
class MyClass {
val: number;
constructor(val: number) {
if (!(this instanceof MyClass)) {
return new MyClass(val);
}
this.val = val;
}
}
Aber anrufen MyClass(5)
gibt mir die Fehlermeldung Value of type 'typeof MyClass' is not callable. Did you mean to include 'new'?
Gibt es eine Möglichkeit, ich kann diese Muster-Arbeit in TypeScript?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Was ist das? Beschreiben Sie die gewünschte Form
MyClass
und den zugehörigen Konstruktor:Beachten Sie, dass
MyClassConstructor
ist definiert als sowohl für callable als Funktion und newable als Konstruktor. Dann setzen Sie es um:Den oben genannten Werken, obwohl es ein paar kleine Falten. Falten: die Implementierung gibt
MyClass | undefined
, und der compiler nicht erkennen, dass dieMyClass
return-Wert entspricht dem aufrufbare Funktion und dieundefined
Wert entspricht der newable Konstruktor... so dass es beschwert. Daher deras MyClassConstructor
am Ende. Falten zwei: diethis
parameter derzeit nicht schmal über control-flow-Analyse, so müssen wir behaupten, dassthis
ist nichtvoid
bei der Festlegung Ihrerval
Eigentum, obwohl zu diesem Zeitpunkt wissen wir, es kann nicht seinvoid
. So haben wir die Verwendung der nicht-null-Behauptung operator!
.Sowieso, Sie können überprüfen, dass diese funktioniert:
Hoffe, das hilft, viel Glück!
UPDATE
Nachteil: wie bereits erwähnt in @Paleo ist Antwort, wenn Ihr Ziel ist ES2015 oder später mit der
class
im Quellcode ausgegeben wirdclass
in Ihrer kompilierten JavaScript, und diejenigen, die erfordernnew()
nach den spec. Ich habe gesehen, Fehler wieTypeError: Class constructors cannot be invoked without 'new'
. Es ist durchaus möglich, dass einige JavaScript-Module zu ignorieren, die Skillung, und gerne akzeptieren-Funktion-Stil fordert auch. Wenn Sie nicht kümmern, diese Warnungen (z.B., Ihr Ziel ist ausdrücklich ES5 oder Sie wissen, du gehst zu laufen in einem von diesen nicht spec-konformen Umgebungen), dann können Sie bestimmt die Kraft, Maschinenschrift, zu gehen zusammen mit, dass:In diesem Fall haben Sie umbenannt
MyClass
aus dem Weg zu_MyClass
, und definiertMyClass
auch ein Typ (der gleiche wie_MyClass
) und einen Wert (der gleiche wie der_MyClass
- Konstruktor, sondern deren Typ behauptet auch aufrufbar sein, wie eine Funktion.) Dies funktioniert zur compile-Zeit, wie oben gesehen. Ob Ihre Laufzeit ist glücklich mit ihm ist vorbehaltlich der Einschränkungen oben. Ich persönlich würde stick an die Funktion Stil in meiner ursprünglichen Antwort, da ich weiß die sind beide aufrufbar und newable in es2015 und später.Glück wieder!
UPDATE 2
Wenn Sie nur auf der Suche nach einem Weg, erklären die Art Ihrer
bindNew()
Funktion von diese Antwort, die eine spec-konformclass
und produziert etwas, was sowohl newable und aufrufbar wie eine Funktion, können Sie etwas wie das hier tun:Dies hat den Effekt, richtig tippe:
Aber Hüte dich vor den überladenen Erklärungen für
bindNew()
arbeiten nicht für jeden möglichen Fall. Genauer gesagt, es funktioniert für Konstruktoren, die bis zu drei Parameter erforderlich. Konstruktoren mit optionalem Parameter oder mehrere überlast-Signaturen wird wahrscheinlich nicht richtig abgeleitet. So müssen Sie möglicherweise zu zwicken die Testungen je nach Anwendungsfall.Okay, hoffe , dass hilft. Viel Glück ein drittes mal.
UPDATE 3, AUG 2018
Typoskript 3.0 eingeführt Tupel in Ruhe und spread-Positionen, so dass wir leicht fertig mit den Funktionen einer beliebigen Anzahl und Typ der Argumente, ohne die oben genannten überlastungen und Einschränkungen. Hier ist die neue Erklärung der
bindNew()
:class
syntax und diebindNew
- Funktion oder die Edel-decorator bereits in meinem genau richtig hier? stackoverflow.com/a/48326964/738768bindNew()
- Funktion)instanceof MyClass
dann? Auch gibt es wirklich keinen besseren Weg, um Typ-variable Anzahl von Argumenten? Das ganze scheint wie viel mehr Mühe, als es Wert ist 🙂instanceof MyClass
zu arbeiten, abhängig von der Implementierung derbindNew()
, aber ich habe es nicht ausprobiert. ... Jetzt, Typoskript als der v2.7 fehlen einige Typ-Operatoren, die Sie würde tun müssen, variable Anzahl von Argumenten "richtig". Sie können nicht überprüfen, eine Funktion Unterschrift odernew()
Signatur zu extrahieren, deren argument-Typen (wahrscheinlich als eine Art Tupel) und den Rückgabetyp.Dem Stichwort
new
ist erforderlich für ES6-Klassen:Lösung mit
instanceof
undextends
arbeitenDas problem mit den meisten von der Lösung, die ich bisher gesehen haben
verwenden
x = X()
stattx = new X()
sind:
x instanceof X
funktioniert nichtclass Y extends X { }
funktioniert nichtconsole.log(x)
Drucke, die einen anderen Typ alsX
x = X()
funktioniert, aberx = new X()
nichtMeine Lösungen
TL;DR - Grundlegende Verwendung
Mithilfe des folgenden Codes (auch auf GitHub, siehe: ts-keine neuen) kann man schreiben:
oder:
statt der üblichen:
nutzen zu können, entweder
a = new A()
odera = A()
mit arbeiten
instanceof
,extends
, richtige Vererbung und Unterstützung für moderne Zusammenstellung von Zielen (einige Lösungen funktionieren nur, wenn transpiled zu ES5 oder älter, denn Sie verlassen sich aufclass
übersetztfunction
die haben unterschiedliche Aufruf-Semantik).Voller Beispiele
#1
#2
#3
#2 Vereinfachtes
#3 vereinfacht
In #1 und #2:
instanceof
funktioniertextends
funktioniertconsole.log
korrekt gedrucktconstructor
Eigenschaft von Instanzen der Punkt, um den echten KonstruktorIn #3:
instanceof
funktioniertextends
funktioniertconsole.log
korrekt gedrucktconstructor
Eigenschaft von Instanzen der Punkt an der exponierten wrapper (das kann ein Vorteil oder Nachteil-je nach den Umständen)Den vereinfachte Versionen bieten nicht alle meta-Daten, die für die Selbstbeobachtung, wenn Sie es nicht brauchen.
Siehe auch
Mein workaround mit einen Typ und eine Funktion:
oder mit einem interface: