Cum să definești o proprietate statică într-o interfață TypeScript
Vreau doar să declar o proprietate statică în interfața TypeScript? Nu am găsit nicăieri informații despre acest lucru.
interface myInterface {
static Name:string;
}
Este posibil?
Răspuns #1
Urmați răspunsul lui @Duncan și @Bartvds, aici pentru a oferi o modalitate funcțională după ce au trecut ani.
În acest moment, după lansarea Typescript 1.5 (15 iunie '15), interfața ta utilă
interface MyType {
instanceMethod();
}
interface MyTypeStatic {
new():MyType;
staticMethod();
}
poate fi implementat în acest mod cu ajutorul decoratorului.
/* 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() {}
}
Consultați comentariul meu la problema 13462 de pe GitHub.
rezultat vizual: Eroare de compilare cu indiciu de metodă statică lipsă.
După ce metoda statică a fost implementată, apare un indiciu pentru metoda lipsă.
Compilarea a trecut după ce atât interfața statică, cât și interfața normală au fost îndeplinite.
Răspuns #2
Nu poți defini o proprietate statică într-o interfață în TypeScript.
Să spunem că vrei să modifici obiectul Date, în loc să încerci să adaugi la definițiile lui Date, ai putea să-l înfășori, sau pur și simplu să-ți creezi propria clasă complexă de date pentru a face lucrurile pe care Date nu le face.
class RichDate {
public static MinValue = new Date();
}
Pentru că Date este o interfață în TypeScript, nu o poți extinde cu o clasă folosind cuvântul cheie extends, ceea ce este puțin păcat, deoarece aceasta ar fi fost o soluție bună dacă Date ar fi fost o clasă.
Dacă doriți să extindeți obiectul Date pentru a furniza o proprietate MinValue pe prototip, puteți:
interface Date {
MinValue: Date;
}
Date.prototype.MinValue = new Date(0);
Apelat folosind:
var x = new Date();
console.log(x.MinValue);
Și dacă vrei să-l faci disponibil fără o instanță, poți să o faci și... dar este puțin ciudat.
interface DateStatic extends Date {
MinValue: Date;
}
Date['MinValue'] = new Date(0);
Apelat folosind:
var x: DateStatic = <any>Date; // We aren't using an instance
console.log(x.MinValue);
Răspunsul #3
Modificatorii statici nu pot apărea pe un membru de tip (TS1070). De aceea, recomand utilizarea unei clase abstracte și a moștenirii pentru a rezolva misiunea:
Exemplu
// 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());
Răspunsul #4
Poți defini interfața în mod normal:
interface MyInterface {
Name:string;
}
dar nu poți pur și simplu să faci
class MyClass implements MyInterface {
static Name:string; // typescript won't care about this field
Name:string; // and demand this one instead
}
Pentru a exprima că o clasă ar trebui să urmeze această interfață pentru proprietățile sale statice, ai nevoie de puțină șmecherie:
var MyClass: MyInterface;
MyClass = class {
static Name:string; // if the class doesn't have that field it won't compile
}
Poți chiar păstra numele clasei, TypeScript (2.0) nu va conta:
var MyClass: MyInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that field it won't compile
}
Dacă vrei să moștenești de la mai multe interfețe static, va trebui mai întâi să le combini într-una nouă:
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
}
Sau dacă nu vrei să numești interfața combinată, poți face:
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
}
Exemplu funcțional
Răspunsul #5
Soluție
Returnează un tip de instanță al I, asigură că I este un constructor concret valid și C extinde I:
type StaticImplements<I extends new (...args: any[]) => any, C extends I> = InstanceType<I>;
Sau o versiune mai generală, care ar trebui să funcționeze pentru mai multe cazuri. Returnează any și se asigură că C extinde I:
type StaticImplements<I, C extends I> = any;
Interfață cu metodă de instanță:
interface MyInstance {
instanceMethod();
}
Interfață cu metodă statică:
interface MyClassStatic {
new (...args: any[]): MyInstance;
staticMethod();
}
Clasă care necesită metodă statică și se extinde cu propria metodă:
class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {
static staticMethod();
static ownStaticMethod();
instanceMethod();
ownInstanceMethod();
}
Note
- Verificarea tipului are loc de fapt în
C extends I - Constrângerea pentru tipul parametrului
Ipoate fi modificată după cum este necesar - Tipul de returnare este ceea ce clasa ajunge să implementeze prin
implements; PentruInstanceType<I>clasa ar implementa de fapt un tip de instanță, deșiobject,{}sauanyar trebui să funcționeze
Raționament
Definirea metodelor statice în interfețe este discutată în #33892, iar metodele statice abstracte sunt discutate în #34516.
Pe baza răspunsurilor lui Val și Aleksey (mulțumesc), această soluție:
- Nu necesită valori suplimentare la timpul de rulare
- Informațiile membrilor proprii ai clasei sunt păstrate
- Permite constrângeri pentru constructor
Test
Așa cum este - Link către terenul de joacă:
MyClass.staticMethod(); // OK
MyClass.ownStaticMethod(); // OK
new MyClass().instanceMethod(); // OK
new MyClass().ownInstanceMethod(); // OK
Dacă eliminați staticMethod din MyClass - Link către Playground:
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'.
Dacă să eliminați instanceMethod din MyClass - Link Playground:
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'.
Răspunsul #6
Proprietățile statice sunt de obicei plasate pe constructorul (global) al obiectului, în timp ce cuvântul cheie „interface” se aplică instanțelor obiectului.
Răspunsul anterior dat este, desigur, corect dacă scrieți clasa în TypeScript. S-ar putea să fie util pentru alții să știe că, dacă descrieți un obiect care este deja implementat în altă parte, atunci constructorul global inclusiv proprietățile statice poate fi declarat astfel:
declare var myInterface : {
new(): Interface;
Name:string;
}


