2013-01-15 11 views
70

W TypeScript, podczas tworzenia plików deklaracji źródłowych .d.ts, co jest lepsze i dlaczego?Jaka jest różnica między "deklaruj klasę" i "interfejs" w TypeScript

declare class Example { 
    public Method(): void; 
} 

lub

interface Example { 
    Method(): void; 
} 

Różnice, które mogę powiedzieć to, że interfejsy nie mogą mieć metody statyczne, więc trzeba użyć klasy dla tego. Oba nie przynoszą żadnych wyników JS, więc może to nie ma znaczenia?

+0

Zobacz http://stackoverflow.com/a/14323673/1704166 –

+0

Nie wydaje mi się, aby któryś z nich naprawdę pomógł opisać, że użyjesz jednego nad drugim, ponieważ oba mogą osiągnąć to samo, bez wyjścia JS. – Chris

Odpowiedz

118

interface jest, gdy chcesz po prostu opisać kształt obiektu. Nie ma generowania kodu dla interfejsów - są one wyłącznie artefaktem w systemie typów. Nie zobaczysz żadnej różnicy w generowaniu kodu dla klasy w zależności od tego, czy ma ona klauzulę implements.

declare class jest, gdy chcemy opisać istniejącą klasy (zwykle klasę maszynopis, ale nie zawsze), który będzie obecny na zewnątrz (na przykład, masz dwie .TS pliki kompilacji dwóch js pliki i oba są zawarte w tagach script na stronie internetowej). Jeśli odziedziczysz po class używając extends (niezależnie od tego, czy podstawowym typem był declare class czy zwykły class), kompilator wygeneruje cały kod, aby podłączyć łańcuch prototypów i konstruktorów forwardujących, a co nie.

Jeśli spróbujesz odziedziczyć po declare class, który powinien być interfejsem, wystąpi błąd środowiska wykonawczego, ponieważ wygenerowany kod będzie odwoływał się do obiektu bez manifestowania środowiska wykonawczego.

Odwrotnie, jeśli po prostu implement interfejs, który powinien był declare class, będziesz musiał ponownie wdrożenia wszystkich członkach siebie i nie będzie wykorzystanie dowolnego kodu ponownego wykorzystania z would- być klasą podstawową, a funkcje sprawdzające łańcuch prototypów w środowisku wykonawczym odrzucają obiekt jako nie będący instancją klasy bazowej.

Aby uzyskać naprawdę nerdy, jeśli masz C++ tła, można z grubsza myśleć interface jak typedef i declare class jako deklaracja konstruktora, który ściśle brakuje definicji w tej jednostce kompilacji extern.

Z czystej strony konsumpcji (pisanie kodu nadrzędną, nie dodając nowe typy), jedyna różnica między interface i declare class jest to, że nie można new interfejs. Jednakże, jeśli zamierzasz extend/implement jeden z tych typów w nowym class, absolutnie musiał wybrać poprawnie między interface i declare class. Tylko jeden z nich zadziała.

Dwie zasady, które będą dobrze służyć:

  • Czy nazwa wyrównywania typu z funkcji konstruktora (coś invokable z new) to rzeczywiście obecny w czasie wykonywania (np Date jest, ale JQueryStatic nie jest) ? Jeśli nr, na pewno chcesz interface
  • Mam do czynienia z skompilowanej klasy z innego pliku TypeScript, czy coś dostatecznie podobne? Jeśli yes użyć declare class
+0

Możesz teraz utworzyć nowy interfejs w maszynopisie. Jedynym ograniczeniem jest dziedziczenie. –

+2

Nie można wywołać operatora 'new' na typie interfejsu. Jednak interfejsy mogą tworzyć sygnatury, co oznacza, że ​​możesz wywołać operatora 'new' na wartości typu interfejsu. To bardzo różni się od tego, jak działa "klasa", gdzie podpis konstrukcji znajduje się na samej nazwie typu, a nie na wyrażeniu tego typu. –

+0

Jeśli wybierzesz trasę dodawania konstruktora do interfejsu, powinien to być TYLKO członek interfejsu, z wyjątkiem "statyki" tej klasy. Nie łącz interfejsu interfejsu konstruktora z interfejsem konstruowanego obiektu. Jeśli tak, system typów zezwala na głupotę, na przykład: new (new x()), gdzie x: Interface. –

12

można zaimplementować interfejs:

class MyClass implements Example { 
    Method() { 

    } 
} 

Podczas gdy składnia declare class jest naprawdę przeznaczone do użycia, aby dodać definicje typów dla kodu zewnętrznego, który nie jest napisany na maszynie - więc realizacja to „gdzie indziej”.

+0

Sugerujesz więc, że deklaruj klasa powinna być używana do opisywania kodu nie napisanego w TypeScript? Zakładam, że w tym przypadku, ale w pliku jquery.d.ts zaznaczonym, JQueryStatic jest interfejsem zaimplementowanym przez: zadeklarować $: JQueryStatic Chciałbym jednak, aby to było zadeklarować klasę publiczną $ { .. } – Chris

+0

Jedyny powód, dla którego mogę myśleć o tym, to gdybyś nie chciał, aby ludzie rozszerzyli klasę - używanie interfejsu oznacza, że ​​będziesz musiał dostarczyć całe wdrożenie. – Fenton

+0

Ma sens. Być może to był powód. – Chris

3

W laika, declare jest stosowany w .ts/d.ts plików poinformować kompilator, że powinniśmy oczekiwać słowa kluczowego jesteśmy declaring istnieć w tym środowisku, nawet jeśli nie jest to zdefiniowane w niniejszym pliku. Umożliwi nam to uzyskanie bezpieczeństwa typu przy korzystaniu z zadeklarowanego obiektu, ponieważ kompilator Typescript wie, że inny składnik może dostarczyć tę zmienną.

Powiązane problemy