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);
})();