Modül ve Ad Alanı - İçe Aktarma ve Türleri Gerektirme


102

Birlikte karışıklık çok alıyorum module/namespace/exportve import, require, referencekullanım. Java kökenli biri olarak, biri bana ne zaman neyi ve doğru tasarımın kullanılacağını kısaca açıklayabilir mi? Örnek proje yazarken batırdığımı hissediyorum

Şimdiye kadar bu benim anlayışım 1. moduleharici paketler için 2. namespacedahili paketler içindir

  • Nasıl kategorize ettiğimizi anlamadım mı?
  • Bir sınıf veya ad alanı veya paket ne zaman dışa aktarılır?
  • Paket / ad alanını dışa aktarırsak, içindeki tüm sınıflar dışa aktarılır veya açıkça dışa aktarılması gerekir.
  • Her biri nasıl ithal edilebilir / istenebilir?

Dokümana göre , her yönetici / model için her "ts" dosyasını oluşturuyorsam, Typescript "ad alanlarının" kullanılmasını önermiyor mu? Doğrudan referans yolları kullanılsın mı?

Farklı geçmişlerden geldiğim ve ES6 / ES5 vb. Hakkında emin olmadığım için lütfen ayrıntılı olarak açıklayın.

Aynı soruları soran / karıştıran birkaç kişi gördüm. Umarım birisi gerçek dünya senaryosuyla ayrıntılı olarak açıklayabilir


bu, sorunuzu yanıtlayan çok dikkat çekiyor, neden ödüllendirildiğinden emin değilim
Dan Pantry

@DanPantry, ödüle başlamadan önce tek bir cevap yoktu :(
Reddy

benim hatam - zaman damgalarını karşılaştırmadım.
Dan Kiler

Yanıtlar:


80

Nasıl kategorize ettiğimizi anlamadım mı?

Ad alanları, kodunuzu düzenlemek / kapsüllemek için kullanılır. Harici modüller, kodunuzu düzenlemek / kapsüllemek VE kodunuzu çalışma zamanında bulmak için kullanılır. Pratikte, çalışma zamanında iki seçeneğiniz vardır: 1) aktarılan tüm kodu tek bir dosyada birleştirin veya 2) harici modülleri kullanın ve birden çok dosyaya sahip olun ve bu dosyalara ulaşmak için başka bir mekanizmaya ihtiyaç duyun.

Bir sınıf veya ad alanı veya paket ne zaman dışa aktarılır?

Bir türü veya değeri, içinde bulunduğu dosyanın dışında görünür kılmak için, bir ad alanının içindeyse onu dışa aktarmanız gerekir. En üst düzeyde mi yoksa bir ad alanı içinde mi dışa aktaracağınız, şimdi harici bir modülde olup olmadığına karar verecektir.

Paket / ad alanını dışa aktarırsak, içindeki tüm sınıflar dışa aktarılır veya açıkça dışa aktarılması gerekir.

Bir ad alanındaki sınıfların, sınıfın tanımlandığı dosyanın dışında derleme zamanında görünür olması için her zaman açıkça dışa aktarılması gerekir.

Her biri nasıl ithal edilebilir / istenebilir?

Bu, harici modüller kullanıp kullanmamanıza bağlıdır. Harici bir modülün onu "kullanması" için her zaman içe aktarılması gerekecektir. Harici bir modülde olmayan bir ad alanını içe aktarmak gerçekten sadece ad alanı için bir takma ad sağlamaktır - yine de tür / her neyse diğer adla önek almanız gerekir (ve bu nedenle ad alanlarını genellikle harici modüllerle kullanmak istemezsiniz; bunu yapmak, harici modül tarafından sağlanan herhangi bir şeye başvururken her zaman bir önek kullanmanız gerektiği anlamına gelir.) Harici bir modülde olmayan ad alanları dosyaları kapsayabilir, bu nedenle aynı ad alanında iseniz, tarafından dışa aktarılan herhangi bir şeye başvurabilirsiniz. herhangi bir içe aktarmaya ihtiyaç duymadan ad alanı.

Yukarıdakileri gerçekten anlamak için biraz arka plan bilgisine ihtiyacınız var. Referanslar / ad alanları / harici modüller ile anlaşılması gereken en önemli şey, bu yapıların derleme zamanında ne yaptıkları ve çalışma zamanında ne yaptıklarıdır.

Tür bilgilerini bulmak için derleme sırasında referans yönergeler kullanılır. Kaynağınızın içinde belirli bir sembol var. TypeScript derleyicisi bu sembolün tanımını nasıl bulur? Başvuru yönergesi, büyük ölçüde tsconfig.json mekanizması tarafından dahil edilmiştir - tsconfig.json kullanarak, derleyiciye tüm kaynaklarınızın nerede olduğunu söylersiniz.

Ad alanları tür tanımları ve / veya uygulama içerebilir. Bir ad alanı yalnızca tür bilgisi içeriyorsa, hiçbir çalışma zamanı bildirimi içermez - bunu JS çıktısına bakarak ve boş bir JS dosyası bularak kontrol edebilirsiniz. Bir ad alanında uygulama kodu varsa, kod ad alanıyla aynı ada sahip bir global değişkene atanan bir kapağın içine sarılır. Yuvalanmış ad alanları ile, kök ad alanı için global bir değişken olacaktır. Tekrar JS çıktısını kontrol edin. Ad alanları, tarihsel olarak JS istemci tarafı kitaplıklarının adlandırma çakışmalarıyla ilgili sorunu önlemeye çalıştığı şekildedir. Buradaki fikir, tüm kitaplığınızı tek bir kapağa sarmak ve ardından mümkün olduğunca küçük bir küresel ayak izini ortaya çıkarmaktır - kapanışa atıfta bulunan yalnızca bir küresel değişken. Sorun şu ki, küresel alanda bir isim talep etmişsiniz. Ya bir kütüphanenin iki versiyonunu isteseydiniz? Bir TypeScript ad alanında hala ad alanı için kaynağın nasıl bulunacağı sorunu vardır. Diğer bir deyişle, AB'ye başvuran kaynak kodu, derleyiciye AB'yi nasıl bulacağını söyleme sorunuyla karşı karşıyadır - ya başvuru yönergelerini kullanarak ya da tsconfig.json kullanarak. Veya ad alanını harici bir modüle koyarak ve ardından harici modülü içe aktararak.

Sunucu tarafı JS ile oluşturulan harici modüller. Bir harici modül ile dosya sistemindeki bir dosya arasında bire bir yazışma vardır. Dış modülleri iç içe geçmiş bir yapıda düzenlemek için dosya sistemi dizin yapısını kullanabilirsiniz. Harici bir modülün içe aktarılması, genellikle o harici modüle bir çalışma zamanı bağımlılığı getirecektir (istisna, harici bir modülü içe aktardığınızda ancak daha sonra dışa aktarmalarının hiçbirini değer konumunda kullanmamanızdır - yani, yalnızca harici modülü içe aktarırsınız. tür bilgisine ulaşmak için). Harici bir modül dolaylı olarak bir kapanış içindedir ve bu anahtardır: modülün kullanıcısı kapanışı istediği yerel değişkene atayabilir. TypeScript / ES6, harici modüllerin dışa aktarımlarını yerel adlarla eşleştirmek için ek sözdizimi ekler, ancak bu sadece bir nezakettir. Sunucu tarafında, harici bir modülü bulmak nispeten basittir: sadece yerel dosya sisteminde harici modülü temsil eden dosyayı bulun. İstemci tarafında harici modülleri bir tarayıcıda kullanmak istiyorsanız, modülün yüklenmeye hazır olduğu dosya sistemine eşdeğer olmadığından daha karmaşık hale gelir. Yani şimdi istemci tarafında, tüm bu dosyaları tarayıcıda uzaktan kullanılabilecek bir formda bir araya getirmenin bir yoluna ihtiyacınız var - bu, Webpack gibi modül paketleyicilerinin olduğu yerdir (Webpack, paket modüllerden çok daha fazlasını yapar) ve Browserify devreye giriyor. Modül paketleyicileri, harici modüllerinizin tarayıcıda çalışma zamanı çözümlemesine izin verir. bir tarayıcıda, modülün yüklenmeye hazır olduğu dosya sistemine eşdeğer olmadığı için daha karmaşık hale gelir. Yani şimdi istemci tarafında, tüm bu dosyaları tarayıcıda uzaktan kullanılabilecek bir formda bir araya getirmenin bir yoluna ihtiyacınız var - bu, Webpack gibi modül paketleyicilerinin olduğu yerdir (Webpack, paket modüllerden çok daha fazlasını yapar) ve Browserify devreye giriyor. Modül paketleyicileri, harici modüllerinizin tarayıcıda çalışma zamanı çözümlemesine izin verir. bir tarayıcıda, modülün yüklenmeye hazır olduğu dosya sistemine eşdeğer olmadığından daha karmaşık hale gelir. Şimdi istemci tarafında, tüm bu dosyaları tarayıcıda uzaktan kullanılabilecek bir formda bir araya getirmenin bir yoluna ihtiyacınız var - bu, Webpack gibi modül paketleyicilerinin olduğu yerdir (Webpack, paket modüllerden çok daha fazlasını yapar) ve Browserify devreye giriyor. Modül paketleyicileri, harici modüllerinizin tarayıcıda çalışma zamanı çözümlemesine izin verir.

Gerçek dünya senaryosu: AngularJS. Harici modüller yokmuş gibi davranın, küresel alan kirliliğini sınırlamak için tek bir ad alanı kullanın (aşağıdaki örnekte tek değişkenli MyApp, global alandaki tek şeydir), yalnızca arayüzleri dışa aktarın ve uygulamaları yapmak için AngularJS bağımlılık enjeksiyonunu kullanın kullanıma hazır. Tüm sınıfları bir dizin köküne yerleştirin, köke bir tsconfig.json ekleyin, aynı dizin köküne angularjs typings'i kurun, böylece tsconfig.json da onu alır, tüm çıktı int bir JS dosyasını birleştirin. Kodun yeniden kullanımı çok önemli değilse, bu çoğu proje için iyi çalışacaktır.

MyService.ts:

namespace MyApp {

    // without an export the interface is not visible outside of MyService.ts
    export interface MyService { 
        ....
    }

    // class is not exported; AngularJS DI will wire up the implementation
    class MyServiceImpl implements MyService {
    }

    angular.module("MyApp").service("myService", MyServiceImpl);
}

MyController.ts:

namespace MyApp {

   class MyController {
       // No import of MyService is needed as we are spanning 
       // one namespace with multiple files.
       // MyService is only used at compile time for type checking. 
       // AngularJS DI is done on the name of the variable. 
       constructor(private myService: MyService) { 
       }
   }
   angular.module("MyApp").controller("myController", MyController);
}

Küresel çalışma süresi kapsamını kirletmekten kaçınmak için IIFE'yi kullanma. Bu örnekte, hiçbir global değişken oluşturulmamıştır. (Bir tsconfig.json varsayılır.)

Foo.ts:

namespace Foo {
    // without an export IFoo is not visible. No JS is generated here
    // as we are only defining a type.
    export interface IFoo {
        x: string;
    }
}

interface ITopLevel {
    z: string;
}

(function(){
    // export required above to make IFoo visible as we are not in the Foo namespace
    class Foo1 implements Foo.IFoo {
        x: string = "abc";
    }
    // do something with Foo1 like register it with a DI system
})();

Bar.ts:

// alias import; no external module created
import IFoo = Foo.IFoo;

(function() {

    // Namespace Foo is always visible as it was defined at
    // top level (outside of any other namespace).
    class Bar1 implements Foo.IFoo {
        x: string;
    }

    // equivalent to above
    class Bar2 implements IFoo {
        x: string;
    }

    // IToplevel is visible here for the same reason namespace Foo is visible
    class MyToplevel implements ITopLevel {
        z: string;
    }

})();

IIFE'yi kullanarak, Uygulamam'ı ilk örnekte global bir değişken olarak tanıtmayı ortadan kaldırabilirsiniz.

MyService.ts:

interface MyService { 
    ....
}

(function() {

    class MyServiceImpl implements MyService {
    }

    angular.module("MyApp").service("myService", MyServiceImpl);
})();

MyController.ts:

(function() { 

   class MyController { 
       constructor(private myService: MyService) { 
       }
   }

   angular.module("MyApp").controller("myController", MyController);
})();

30

İki şey var:

  • TypeScript'teki bir modül standart bir ES6 kavramıdır, kodun en üst düzeyindeimport / exportanahtar sözcüklerini kullanır ;
  • Bir ad eski bir moda kodunu düzenlemek için yardımına typescript bir kavram özgüdür.

İsim alanları

Neredeyse modası geçmiş bir kavramdır. ES6 modüllerinden önce, bir tarayıcıda JavaScript kodunu ayırmanın yaygın yolu, genel değişkenler oluşturmaktı. Örneğin, bir API'nin alt çizgi gibi tüm işlevleri, adlı global bir değişkende bulunuyordu _.

Bu eski yöntem, Java paketleri veya PHP ad alanları gibidir. Web'e uyarlanmamıştır. Yeni ECMAScript standardı aşağıdaki gibi sorunları çözer: aynı ada sahip iki kitaplık nasıl kullanılır? Aynı kütüphanenin iki farklı versiyonu nasıl kullanılır?

Not: ECMAScript “modüller” tanımından önceki TypeScript sürümlerinde (2014 yazı), ad alanları “dahili modüller” ve modüller “harici modüller” olarak adlandırılırdı.

Uyarı 2: exporta içindeki namespaceanahtar kelime, anahtar kelimenin standart olmayan TypeScript kullanımıdır. Ad alanının dışından halka açık bir şekilde erişilebilen bir şeyi beyan etmenin yoludur.

ES6 modülleri

Modül, anahtar sözcükleri içeren importveya exportkodun en üst düzeyinde bulunan bir dosyadır .

TypeScript, ECMAScript standardına uygundur. Mozilla'dan bir makalede ES6 modüllerine iyi bir giriş okumanızı öneririm .

Bir ön uç uygulamasında (bir tarayıcıda) modülleri kullanmak istiyorsanız, bir paketleyici ( Webpack [ dokümantasyon burada ], Browserify) veya bir yükleyici ( SystemJS [ burada bir eğitim ], RequireJS) kullanmanız gerekir ve TypeScript'i bu ortamla yapılandırmak için.

Kodunuz Node.js'de çalıştırılıyorsa, yalnızca TypeScript derleyicisini CommonJS biçimini oluşturacak şekilde yapılandırın.

Uyarı: Bir modülde bir isim alanı bildirilebilir. Bu durumda, modül dışından global bir değişken olarak erişilemez. Ancak modülden ihraç edilebilir.


Typecript derleyicisi modülleri otomatik olarak tek bir .js dosyasında paketlemiyor mu?
Kokodoko

@Kokodoko, Hayır. Sadece bitiştirebilir.
Paleo

Erm ... fark nedir? .... Tek bir .js dosyası oluşturmak için modüller ve yalnızca tsc kullanıyorum. SystemJS, webpack veya browsererify kullanmam gerekmiyor.
Kokodoko

1
@Kokodoko Haklısın! Benim hatam! Görünüşe göre TypeScript derleyicisi TS 1.8'den beri bir paket oluşturabiliyor , ben özelliği kaçırmıştım.
Paleo

Olduğu söyleniyor ... Modüllerim derleniyor ancak SystemJS.import ('/ js / main.js') sonrasında çalışmıyor; Uygulamayı nasıl başlatacağınıza dair bir fikriniz var mı?
Kokodoko

14
  1. modül harici paketler içindir 2. ad alanı dahili paketler içindir

Aslında moduleanahtar kelime, anahtar kelime ile değiştirildi namespace.

Bu nedenle daha iyi bir ifade, Modüller eskiden harici modüller, ad alanı ise dahili modüller olarak adlandırılan şeydir.

Daha

Bunun daha fazla yardımcı olacağını umuyoruz: https://basarat.gitbooks.io/typescript/content/docs/project/modules.html


8
bilgilendirdiğim için üzgünüm, sorular cevapsız. Ders kitabı tanımından ziyade gerçek dünya örneği ile detaylı bir şekilde açıklamayı bekliyordum.
Reddy

Şu anda TypeScript'te bir modül klavyesi olmadığını mı söylüyorsunuz?
Mohammad Kermani

7

" gerekli " ve " içe aktarma " işlevsellik açısından eşdeğerdir. her ikisini de birbirinin yerine kullanabiliriz çünkü tarayıcının onları yerel olarak destekleyip desteklemediğini gerçekten önemsemeyen aktarıcılarımız var. ancak " gerekli " kelimesinin kökleri CommonJS'den 2009'a kadar uzanan eski kodlama stiline sahipken, "içe aktarma" sözdizimini yaygın olarak kabul edilen ES6 (ES2015) sözdiziminden türetir. bu nedenle yeni projeler için " içe aktar " kullanmalı ve " gerekli " olmamalısınız .


1
Kesinlikle. Çok kafa karıştırıcı ve bu konuda çok az bilgi, temelde aynı olduğunu söylüyor. Acaba bu neden reddedildi?
Shai Petel

0

Adlandırma Karmaşıklığı

Typescript'in ilk günlerinde, ad alanlarına dahili modüller ve ES6 Modülleri harici modüller olarak adlandırılıyordu .

Artık ad alanlarını bildirmek için, Typescript ekibi , harici modüllerle adlandırma karışıklığını önlemek için sözdizimi namespace { }yerine 'nin kullanılmasını önerir module { }. Çünkü harici modüller artık basitçe "modüller" ve dahili modüller "ad alanları" dır.


İsim alanları

Beyanname

Typescript'teki bir ad alanı, namespaceveya moduleanahtar sözcüğü kullanılarak bildirilebilir . Her iki anahtar kelime de aynı şeyi yapar. Ardından, exportanahtar kelimeyi kullanarak ad alanımızın hangi bölümünü herkese açık hale getireceğimize karar verebiliriz .

// LivingThings.ts
export namespace Animals {
    export class Dog { }
    export class Cat { }
}
export namespace Plants {
    export class Orchid { }
    export class Bamboo { }
}

// LivingThingsUser.ts
import { Animals, Plants } from "./LivingThings"

Mantıksal Gruplama

ES6'dan önce, TypeScript'te ad alanları, bir grup ilgili işlevselliği desteklemek ve uygulama ayrıntılarını gizlemek için arabirimleri, sınıfları, işlevleri ve değişkenleri kapsüllemek için kullanılıyordu. Bu şekilde değişkenlerin küresel alana sızmasını önleyebiliriz. Bu, daha iyi kod organizasyonuna ve ad çakışmalarını önlemeye yardımcı oldu. Şimdi bunu başarmak için ES6 modüllerinin kullanılması önerilir.

Ad alanları artık ortam ad alanı bildirimleri için kullanılmaktadır.

Tek Dosya Kullanımı

Ad alanlarını birden çok dosyada tanımlayabiliriz ve bunlar --outFilebayrak kullanılarak birleştirilebilir . Daha sonra bu birleştirilmiş dosyayı <script>HTML sayfamızdaki etiketin içinde kullanabiliriz . Bu, kodumuzu, tüm bağımlılıkları içeren bir istemci tarafı web uygulamasında iyi bir şekilde yapılandırmamızı sağlar.


Modüller

Beyanname

Modüller ayrıca ES6 modülleri olarak adlandırılır. İlgili işlevleri gruplamak için birden fazla dosya kullanıyoruz ve sadece exportistenen nesneyi herkese açık hale getirmek için anahtar kelimeyi kullanıyoruz .

// Animals.ts
export class Dog { }
export class Cat { }

// Plants.ts
export class Orchid { }
export class Bamboo { }

// LivingThingsUser.ts
import { Dog, Cat } from "./Animals"
import { Orchid, Bamboo } from "./Plants"

Mantıksal Gruplama

Modüllerdeki mantıksal gruplama, ilgili işlevleri gruplamak için ayrı dosyalar kullanılarak elde edilir. Bu nedenle, harici modüllere dosya modülleri de denir .

Tek Dosya Kullanımı

<script>Etiketi kullanarak istemci tarafı web uygulamasının modüllerini yüklemiyoruz çünkü tarayıcılar aynı anda çok sayıda dosya indirirken ve sayfayı işlerken yavaşlayabilir. Bunun için, dosyaları eşzamansız olarak yüklememizi veya harici modül dosyalarını tek bir optimize edilmiş dosyada birleştirmemizi sağlayan CommonJS, AMD, SystemJS gibi modül yükleyicileri kullanıyoruz.

Sunucu tarafı için, özellikle Node.js'de, modüller şiddetle tavsiye edilir.

Bu kadar!

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.