Wie definiert man eine statische Eigenschaft in einem TypeScript-Interface
Ich möchte nur eine statische Eigenschaft in einem TypeScript-Interface deklarieren? Ich habe nirgendwo darüber etwas gefunden.
interface myInterface {
static Name:string;
}
Ist es möglich?
Antwort #1
Folgen Sie @Duncans @Bartvds Antwort, hier um nach Jahren eine brauchbare Möglichkeit zu bieten.
Zu diesem Zeitpunkt nach der Veröffentlichung von Typescript 1.5 (am 15. Juni '15), Ihr hilfreiches Interface
interface MyType {
instanceMethod();
}
interface MyTypeStatic {
new():MyType;
staticMethod();
}
kann auf diese Weise mit Hilfe eines Dekorators implementiert werden.
/* class decorator */
function staticImplements<T>() {
return <U extends T>(constructor: U) => {constructor};
}
@staticImplements<MyTypeStatic>() /* this statement implements both normal interface & static interface */
class MyTypeClass { /* implements MyType { */ /* so this become optional not required */
public static staticMethod() {}
instanceMethod() {}
}
Beziehen Sie sich auf meinen Kommentar bei GitHub-Issue 13462.
Visuelles Ergebnis: Kompilierungsfehler mit Hinweis auf fehlende statische Methode.
Nachdem die statische Methode implementiert wurde, fehlt ein Hinweis auf die Methode.
Die Kompilierung wurde bestanden, nachdem sowohl die statische Schnittstelle als auch die normale Schnittstelle erfüllt wurden.
Antwort #2
Sie können in TypeScript keine statische Eigenschaft in einem Interface definieren.
Angenommen, Sie wollten das Date-Objekt ändern, anstatt zu versuchen, die Definitionen von Date zu erweitern, könnten Sie es umhüllen oder einfach Ihre eigene reichhaltige Datums-Klasse erstellen, um die Dinge zu tun, die Date nicht kann.
class RichDate {
public static MinValue = new Date();
}
Da Date ein Interface in TypeScript ist, können Sie es nicht mit einer Klasse unter Verwendung des extends-Schlüsselworts erweitern, was ein bisschen schade ist, da dies eine gute Lösung wäre, wenn Date eine Klasse wäre.
Wenn Sie das Date-Objekt erweitern möchten, um eine MinValue-Eigenschaft am Prototyp bereitzustellen, können Sie:
interface Date {
MinValue: Date;
}
Date.prototype.MinValue = new Date(0);
Aufgerufen mit:
var x = new Date();
console.log(x.MinValue);
Und wenn Sie es ohne eine Instanz verfügbar machen wollen, können Sie das auch... aber es ist ein bisschen mühsam.
interface DateStatic extends Date {
MinValue: Date;
}
Date['MinValue'] = new Date(0);
Aufgerufen mit:
var x: DateStatic = <any>Date; // We aren't using an instance
console.log(x.MinValue);
Antwort #3
Statische Modifikatoren können nicht an einem Typmitglied erscheinen (TS1070). Deshalb empfehle ich die Verwendung einer abstrakten Klasse und Vererbung, um die Aufgabe zu lösen:
Beispiel
// Interface definition
abstract class MyInterface {
static MyName: string;
abstract getText(): string;
}
// Interface implementation
class MyClass extends MyInterface {
static MyName = 'TestName';
getText(): string {
return `This is my name static name "${MyClass.MyName}".`;
}
}
// Test run
const test: MyInterface = new MyClass();
console.log(test.getText());
Antwort #4
Sie können ein Interface normal definieren:
interface MyInterface {
Name:string;
}
aber du kannst einfach nicht tun
class MyClass implements MyInterface {
static Name:string; // typescript won't care about this field
Name:string; // and demand this one instead
}
Um auszudrücken, dass eine Klasse dieses Interface für ihre statischen Eigenschaften folgen sollte, benötigt man ein wenig Trickserei:
var MyClass: MyInterface;
MyClass = class {
static Name:string; // if the class doesn't have that field it won't compile
}
Du kannst sogar den Namen der Klasse beibehalten, TypeScript (2.0) wird es nicht stören:
var MyClass: MyInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that field it won't compile
}
Wenn Sie von vielen Schnittstellen statisch erben möchten, müssen Sie sie zuerst in einer neuen zusammenführen:
interface NameInterface {
Name:string;
}
interface AddressInterface {
Address:string;
}
interface NameAndAddressInterface extends NameInterface, AddressInterface { }
var MyClass: NameAndAddressInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that static field code won't compile
static Address:string; // if the class doesn't have that static field code won't compile
}
Oder wenn Sie dem zusammengeführten Interface keinen Namen geben möchten, können Sie Folgendes tun:
interface NameInterface {
Name:string;
}
interface AddressInterface {
Address:string;
}
var MyClass: NameInterface & AddressInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that static field code won't compile
static Address:string; // if the class doesn't have that static field code won't compile
}
Funktionierendes Beispiel
Antwort #5
Lösung
Gibt einen Instanztyp von I zurück, stellt sicher, dass I ein gültiger konkreter Konstruktor ist und C I erweitert:
type StaticImplements<I extends new (...args: any[]) => any, C extends I> = InstanceType<I>;
Oder eine allgemeinere Version, die für mehr Fälle funktionieren sollte. Gibt any zurück und stellt sicher, dass C I erweitert:
type StaticImplements<I, C extends I> = any;
Schnittstelle mit Instanzmethode:
interface MyInstance {
instanceMethod();
}
Schnittstelle mit statischer Methode:
interface MyClassStatic {
new (...args: any[]): MyInstance;
staticMethod();
}
Klasse, die eine statische Methode verlangt und mit eigener Methode erweitert:
class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {
static staticMethod();
static ownStaticMethod();
instanceMethod();
ownInstanceMethod();
}
Notizen
- Die Typüberprüfung erfolgt tatsächlich in
C extends I - Die Einschränkung für den Parametertyp
Ikann bei Bedarf geändert werden - Der Rückgabewert ist das, was die Klasse tatsächlich über
implementsimplementiert; FürInstanceType<I>würde die Klasse tatsächlich einen Instanztyp implementieren, obwohlobject,{}oderanyfunktionieren sollten
Begründung
Die Definition statischer Methoden in Schnittstellen wird in #33892 diskutiert, und abstrakte statische Methoden werden in #34516 diskutiert.
Basierend auf Val's und Aleksey's Antworten (danke), diese Lösung:
- Erfordert keine zusätzlichen Laufzeitwerte
- Eigene Mitgliederinformationen der Klasse werden gespeichert
- Erlaubt Konstruktorbeschränkungen
Test
Wie es ist - Spielplatz-Link:
MyClass.staticMethod(); // OK
MyClass.ownStaticMethod(); // OK
new MyClass().instanceMethod(); // OK
new MyClass().ownInstanceMethod(); // OK
Wenn man staticMethod aus MyClass entfernen möchte - Playground-Link:
class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {} // Type 'typeof MyClass' does not satisfy the constraint 'MyClassStatic'. Property 'staticMethod' is missing in type 'typeof MyClass' but required in type 'MyClassStatic'.
Wenn man instanceMethod aus MyClass entfernen möchte - Playground-Link:
class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {} // Class 'MyClass' incorrectly implements interface 'MyInstance'. Property 'instanceMethod' is missing in type 'MyClass' but required in type 'MyInstance'.
Antwort #6
Statische Eigenschaften werden normalerweise auf dem (globalen) Konstruktor des Objekts platziert, während das Schlüsselwort „interface“ auf Instanzen des Objekts angewendet wird.
Die zuvor gegebene Antwort ist natürlich korrekt, wenn Sie die Klasse in TypeScript schreiben. Es könnte anderen helfen zu wissen, dass, wenn Sie ein Objekt beschreiben, das bereits anderswo implementiert ist, der globale Konstruktor einschließlich statischer Eigenschaften so deklariert werden kann:
declare var myInterface : {
new(): Interface;
Name:string;
}


