TypeScript'te "sınıf bildirimi" ve "arabirim" arasındaki fark nedir


116

TypeScript'te, .d.ts kaynak bildirim dosyalarını oluştururken hangisi tercih edilir ve neden?

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

veya

interface Example {
    Method(): void;
}

Söyleyebileceğim farklılıklar, arabirimlerin statik yöntemlere sahip olamayacağıdır, bu nedenle bunun için bir sınıf kullanmanız gerekir. Her ikisi de herhangi bir JS çıktısı üretmiyor, bu yüzden belki de önemli değil?



İkisi de aynı şeyi JS çıktısı olmadan gerçekleştirebildikleri için, bunların ikisinin de birbirini kullanacağınızı açıklamaya gerçekten yardımcı olduğunu düşünmüyorum.
Chris

1
Kısa: declare ile, sınıfın uygulanmasının çalışma zamanında bir arabirimle yapmanız gerekmediğinden emin olmanız gerekir.
Hakim

Yanıtlar:


163

interfacesadece bir nesnenin şeklini tanımlamak istediğiniz zamanlar içindir. Arayüzler için hiçbir zaman kod üretimi yoktur - bunlar yalnızca tür sistemindeki bir yapıdır. Bir implementscümlesi olup olmamasına bağlı olarak, bir sınıf için kod oluşturmada hiçbir fark görmeyeceksiniz .

declare classharici olarak mevcut olacak mevcut bir sınıfı (genellikle bir TypeScript sınıfı, ancak her zaman değil) tanımlamak istediğinizde kullanılır (örneğin, iki .js dosyası olarak derlenen ve her ikisi de scriptetiketler aracılığıyla dahil edilen iki .ts dosyanız vardır bir web sayfasında). Eğer bir devralan varsa classkullanılarak extends(bakılmaksızın baz tipi bir olup olmadığı declare classveya düzenli classderleyici prototip zinciri ve yönlendirme kurucular ve ne değil kanca tüm kodu oluşturmak için gidiyor).

declare classArayüz olması gereken bir cihazdan devralmaya çalışırsanız , bir çalışma zamanı hatası alırsınız çünkü üretilen kod, çalışma zamanı belirtisi olmayan bir nesneye atıfta bulunacaktır.

Tersine, basitçe implementbir arayüz olması gereken bir arabirimseniz, declare classtüm üyeleri kendiniz yeniden uygulamanız gerekecek ve olası temel sınıftan ve işlevlerden herhangi bir kodun yeniden kullanımından yararlanamayacaksınız. çalışma zamanında prototip zincirinin kontrol edilmesi, aslında temel sınıfın bir örneği olmadığı için nesnenizi reddeder.

Gerçekten inek olmak için, eğer bir C ++ arka planınız varsa, kabaca bu derleme biriminde bir tanımı kesinlikle bulunmayan bir kurucu beyanı interfaceolarak typedefve declare classolarak düşünebilirsiniz extern.

Saf bir tüketim taraftan, arasındaki tek fark (değil yeni türlerini ekleme, zorunlu kod yazmak) interfaceve declare classbir yapamazsın ki newbir arayüz. Eğer niyetinde Ancak, extend/ implementyeni bu türlerinden biri class, kesinlikle arasındaki doğru seçmiş zorunda interfaceve declare class. Sadece biri çalışacak.

Size iyi hizmet edecek iki kural:

  • Türün adı, newaslında çalışma zamanında mevcut olan (örneğin Date, ama JQueryStaticdeğil) bir yapıcı işleviyle (çağrılabilir bir şey) hizalı mı? Eğer hiçbir , kesinlikle istiyoruminterface
  • Başka bir TypeScript dosyasından derlenmiş bir sınıfla mı yoksa yeterince benzer bir şeyle mi uğraşıyorum? Eğer evet , kullanımdeclare class

Aslında typcript'te bir arayüz yenileyebilirsiniz. Tek sınırlama kalıtımdır.
Oleg Mihailik

3
newOperatörü bir arabirim türünde çağıramazsınız . Bununla birlikte, arabirimler inşa imzalarına sahip olabilir, bu da newoperatörü arabirim türünün bir değeri üzerinde çağırabileceğiniz anlamına gelir . Bu, classyapı imzasının o türden bir ifade yerine tür adının kendisinde olduğu işleyişinden çok farklıdır .
Ryan Cavanaugh

Arayüze bir kurucu ekleme yoluna giderseniz, sınıfın 'statiği' dışında, arayüzün YALNIZCA üyesi olmalıdır. Yapıcı işlevinin arabirimini, oluşturulan nesnenin arabirimi ile birleştirmeyin. Bunu yaparsanız, tip sistemi şu gibi aptallığa izin verir: new (new x ()), burada x: Interface.
Jeremy Bell

24

Arayüzü uygulayabilirsiniz:

class MyClass implements Example {
    Method() {

    }
}

Oysa declare classuygulama "başka yerde" bu yüzden - sözdizimi gerçekten amaçlanmaktadır daktilo yazılmaz harici kod için tip tanımları eklemek için kullanılacak.


Yani, declare sınıfının TypeScript'te yazılmayan kodu tanımlamak için kullanılması gerektiğini mi söylüyorsunuz? Durumun böyle olduğunu varsayabilirim, ancak kontrol edilen jquery.d.ts dosyasında, JQueryStatic tarafından uygulanan bir arayüz: var $ beyan et: JQueryStatic Bunun $ {public static ...} sınıfını bildirmesine rağmen olurdu
Chris

Bunun için düşünebilmemin tek nedeni, insanların sınıfı genişletmesini istememeniz olabilir - arayüzü kullanmak, tüm uygulamayı sağlamanız gerektiği anlamına gelir.
Fenton

Mantıklı. Belki de nedeni buydu.
Chris

Tamam o zaman, bu yüzden başka bir JS kitaplığındaki bildirimleri göstermeye çalışıyorum, bu yüzden kesinlikle beyan etmem gerekiyor. Kod, bazı kütüphane işlevlerinde (sınıflarda) statiği kullanıyor - şimdiye kadar, bir bildirim dosyasında ifade edilen statik bir özelliği veya yöntemi görmedim. Oh, ve ad alanı veya modül kullanmalı mıyım?
jenson-button-event

13

Layman'ın terimleriyle, / files içinde, derleyiciye , mevcut dosyada tanımlanmamış olsa bile, o ortamda var olmamızı beklememiz gerektiğini söylemek için declarekullanılır . Bu, daha sonra, Typescript derleyicisi artık başka bir bileşenin bu değişkeni sağlayabileceğini bildiğinden, bildirilen nesneyi kullanırken tür güvenliğine sahip olmamızı sağlayacaktır..tsd.tsdeclaring


6

TS arasındaki declareve interfaceiçindeki fark :

bildirmek:

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

Yukarıdaki kodda declare, TS derleyicisinin sınıfın bir yerde Examplebildirildiğini bilmesini sağlar . Bu, sınıfın sihirli bir şekilde dahil edildiği anlamına gelmez. Bir programcı olarak, sınıfınızı ( declareanahtar sözcükle) açıklarken sınıfın mevcut olmasından sorumlusunuz .

arayüz:

interface Example {
    Method(): void;
}

An interface, yalnızca typcript içinde bulunan sanal bir yapıdır. Daktilo yazımı derleyicisi, bunu yalnızca tür denetimi amacıyla kullanır. Kod javascript'e derlendiğinde tüm bu yapı çıkarılacaktır. Typecript derleyicisi, nesnelerin doğru yapıya sahip olup olmadığını kontrol etmek için arayüzler kullanır.

Örneğin aşağıdaki arayüze sahip olduğumuzda:

interface test {
  foo: number,
  bar: string,
}

Bu arayüz tipine sahip tanımladığımız nesnelerin arayüzle tam olarak eşleşmesi gerekir:

// perfect match has all the properties with the right types, TS compiler will not complain.
  const obj1: test = {   
    foo: 5,
    bar: 'hey',
  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.