2012-12-19 23 views

Odpowiedz

27

Nie można zdefiniować właściwości statycznej na interfejsie w TypeScript.

Powiedzmy, że chciał zmienić obiekt Date, zamiast próbować dodać do definicji Date, można go owinąć, albo po prostu stworzyć swoją datę bogatą klasę do zrobienia rzeczy, które Date nie robi.

class RichDate { 
    public static MinValue = new Date(); 
} 

Ponieważ data jest interfejs w maszynopisie, nie można przedłużyć go z klasy za pomocą extends słowa kluczowego, który jest trochę szkoda, ponieważ byłoby to dobre rozwiązanie, jeśli data była klasa.

Jeśli chcesz przedłużyć obiekt Date aby zapewnić nieruchomość MinValue na prototypie można:

interface Date { 
    MinValue: Date; 
} 

Date.prototype.MinValue = new Date(0); 

Wywoływana przy użyciu:

var x = new Date(); 
console.log(x.MinValue); 

A jeśli chcemy, aby było dostępne bez instancja, ty też możesz ... ale jest trochę wybredna.

interface DateStatic extends Date { 
    MinValue: Date; 
} 

Date['MinValue'] = new Date(0); 

Wywoływana przy użyciu:

var x: DateStatic = <any>Date; // We aren't using an instance 
console.log(x.MinValue); 
+1

@Rajagopal Aby było jasne, można rzeczywiście rozszerzyć interfejsy w TS za pomocą słowa kluczowego 'extends'. Po prostu nie można rozszerzyć interfejsu o klasę (co trzeba zrobić, aby dodać właściwość statyczną). – JcFx

+0

Steve - "Ponieważ Date jest interfejsem w TypeScript, nie można go rozszerzyć za pomocą słowa kluczowego extends" - to nieprawda, czyż nie? – JcFx

+1

Możesz rozszerzyć interfejs, ale nie możesz go rozszerzyć o klasę, tylko ją zaimplementuj. Nie wyjaśniłem tego. – Fenton

12

Właściwości statyczne są zwykle umieszczone na (globalne) Konstruktor dla obiektu, natomiast „interfejs” słowo kluczowe odnosi się do instancji obiektu.

Poprzednia udzielona odpowiedź jest oczywiście poprawna, jeśli piszesz klasę w TypeScript. To może pomóc innym, aby wiedzieć, że jeśli opisując obiekt, który jest już realizowany w innym miejscu, wówczas globalny konstruktor tym właściwości statyczne mogą być zadeklarowane tak:

declare var myInterface : { 
    new(): Interface; 
    Name:string; 
} 
+0

edytuj: opublikowano jako pełną odpowiedź [poniżej] (http://stackoverflow.com/a/18837239/1026362) – Bartvds

+0

W tym momencie po wydaniu Dokumentu Typu 1.5 (6.15.2015), jest to praktyczny sposób opisu elementów statycznych klasy. http://stackoverflow.com/a/43674389/681830 – Val

6

@ rozwiązania Duncana powyżej określenie new() dla statycznych prac typu również z interfejsami:

interface MyType { 
    instanceMethod(); 
} 

interface MyTypeStatic { 
    new():MyType; 
    staticMethod(); 
} 
+0

Który z nich byłby moją "implementacją" mojej klasy? –

+1

W tym momencie nie można używać interfejsu do opisu statycznych członków, a jedynie członków instancji. W tym przykładzie twoja klasa implementowałaby 'MyType' (jak w' class Foo implementuje MyType'). Interfejs statyczny jest bardzo przydatny w definicjach podczas opisywania istniejącego kodu JS. – Bartvds

+0

W tym momencie po wydaniu Dokumentu Typu 1.5 (6.15.2015), jest to praktyczny sposób opisu statycznych członków klasy. http://stackoverflow.com/a/43674389/681830 – Val

3

Jeśli chcesz zdefiniować klasę statyczną (np.wszystkie metody/właściwości są statyczne), można zrobić coś takiego:

interface MyStaticClassInterface { 
    foo():string; 
} 

var myStaticClass:MyStaticClassInterface = { 
    foo() { 
    return 'bar'; 
    } 
}; 

W tym przypadku statyczna „klasa” jest naprawdę tylko zwykły ol'-js-przedmiot, który realizuje wszystkie metody MyStaticClassInterface

6

można zdefiniować interfejs normalnie:

interface MyInterface { 
    Name:string; 
} 

ale nie można po prostu zrobić

class MyClass implements MyInterface { 
    static Name:string; // typescript won't care about this field 
    Name:string;   // and demand this one instead 
} 

Aby wyrazić, że klasa powinna śledzić ten interfejs ze swoich właściwości statycznych trzeba trochę sztuczek:

var MyClass: MyInterface; 
MyClass = class { 
    static Name:string; // if the class doesn't have that field it won't compile 
} 

Można nawet zachować nazwę klasy, maszynopis (2.0) nie będzie miał nic przeciwko :

var MyClass: MyInterface; 
MyClass = class MyClass { 
    static Name:string; // if the class doesn't have that field it won't compile 
} 

Jeśli wa do dziedziczenia z wieloma interfejsami statycznie musisz połączyć je najpierw na nowe:

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 
} 

Lub jeśli nie chcesz, aby wymienić połączyła interfejs można zrobić:

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 
} 

Praca example

+0

Otrzymuję błąd TS2322: Anonimowa klasa nie jest przypisywana do typu – JoshuaDavid

+0

@FireCoding Którą wersję języka TypeScript używasz? Moje przykłady zadziałały z 2.0 –

0

Można merge interface with namespace stosując tę ​​samą nazwę:

interface myInterface { } 

namespace myInterface { 
    Name:string; 
} 

Ale ten interfejs jest przydatne tylko, aby wiedzieć, że ma on własność Name. Nie możesz go wdrożyć.

20

Postępuj zgodnie z @ odpowiedź Duncan @ @ Bartvds, tutaj, aby zapewnić sprawny sposób po latach minęło.

W tym momencie po maszynopis 1.5 wydany (@Jun 15 '15), twoja jako interfejs

interface MyType { 
    instanceMethod(); 
} 

interface MyTypeStatic { 
    new():MyType; 
    staticMethod(); 
} 

mogą być realizowane w ten sposób z pomocą dekoratora.

/* class decorator */ 
function staticImplements<T>() { 
    return (constructor: T) => {} 
} 

@staticImplements<MyTypeStatic>() /* this statement implements both normal interface & static interface */ 
class MyTypeClass { /* implements MyType { */ /* so this become optional not required */ 
    public static staticMethod() {} 
    instanceMethod() {} 
} 

Zobacz mój komentarz na github open issue 13462.

Wynik wizualny: Błąd kompilacji z brakującą podpowiedzią metody statycznej. enter image description here

Po wprowadzeniu metody statycznej, brak podpowiedzi dla metody. enter image description here

Kompilacja przekazana po spełnieniu zarówno interfejsu statycznego, jak i normalnego interfejsu. enter image description here

+2

Twoja odpowiedź brzmi: odpowiedź. Dziękuję bardzo. Praca z typem skryptu 2.4.1 –

0

Dla tych, którzy chcą dodać metodę statyczną do wbudowanego obiektu, jak data, łatwo

interface DateConstructor { 
    fromServerDate: any 
} 

A teraz Date.fromServerDate(appt.changeDate) skompiluje porządku.

+0

Skąd się wzięło 'DateConstructor'? – blockhead

1

Znalazłem sposób to zrobić (bez dekoratorów) dla mojego konkretnego przypadku użycia.

Ważną część, która sprawdza członków statycznych jest IObjectClass i korzystania cls: IObjectClass<T> w metodzie createObject:

//------------------------ 
// Library 
//------------------------ 
interface IObject { 
    id: number; 
} 
interface IObjectClass<T> { 
    new(): T; 
    table_name: string; 
} 
function createObject<T extends IObject>(cls: IObjectClass<T>, data:Partial<T>):T { 
    let obj:T = (<any>Object).assign({}, 
    data, 
    { 
     id: 1, 
     table_name: cls.table_name, 
    } 
) 
    return obj; 
} 

//------------------------ 
// Implementation 
//------------------------ 
export class User implements IObject { 
    static table_name: string = 'user'; 
    id: number; 
    name: string; 
} 

//------------------------ 
// Application 
//------------------------ 
let user = createObject(User, {name: 'Jimmy'}); 
console.log(user.name); 
Powiązane problemy