Analogi Piala Permen
Versi 1: Gelas untuk setiap permen
Katakanlah Anda menulis beberapa kode seperti ini:
Mod1.ts
export namespace A {
export class Twix { ... }
}
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Mod3.ts
export namespace A {
export class KitKat { ... }
}
Anda telah membuat pengaturan ini:
Setiap modul (lembaran kertas) diberi nama cangkirnya sendiriA
. Ini tidak berguna - Anda tidak benar - benar mengatur permen Anda di sini, Anda hanya menambahkan langkah tambahan (mengeluarkannya dari cangkir) antara Anda dan camilan.
Versi 2: Satu cangkir dalam lingkup global
Jika Anda tidak menggunakan modul, Anda dapat menulis kode seperti ini (perhatikan kurangnya export
deklarasi):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
Kode ini menciptakan ruang nama gabungan A
di lingkup global:
Pengaturan ini berguna, tetapi tidak berlaku untuk modul (karena modul tidak mencemari lingkup global).
Versi 3: Tanpa cangkir
Kembali ke contoh asli, cangkir A
, A
dan A
tidak melakukan apapun nikmat. Sebagai gantinya, Anda dapat menulis kode sebagai:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
untuk membuat gambar yang terlihat seperti ini:
Jauh lebih baik!
Sekarang, jika Anda masih berpikir tentang seberapa besar Anda benar-benar ingin menggunakan namespace dengan modul Anda, baca terus ...
Ini Bukan Konsep yang Anda Cari
Kita perlu kembali ke asal-usul mengapa ruang nama ada di tempat pertama dan memeriksa apakah alasan itu masuk akal untuk modul eksternal.
Organisasi : Ruang nama berguna untuk mengelompokkan objek dan tipe yang berhubungan secara logis. Misalnya, dalam C #, Anda akan menemukan semua jenis koleksi di System.Collections
. Dengan mengatur jenis kami ke dalam ruang nama hierarkis, kami memberikan pengalaman "penemuan" yang bagus untuk pengguna jenis itu.
Konflik Nama : Ruang nama penting untuk menghindari penamaan tabrakan. Misalnya, Anda mungkin memiliki My.Application.Customer.AddForm
dan My.Application.Order.AddForm
- dua jenis dengan nama yang sama, tetapi ruang nama yang berbeda. Dalam bahasa di mana semua pengidentifikasi ada dalam ruang lingkup root yang sama dan semua majelis memuat semua jenis, sangat penting untuk memiliki semuanya di namespace.
Apakah alasan itu masuk akal dalam modul eksternal?
Organisasi : Modul eksternal sudah ada dalam sistem file, tentu saja. Kita harus menyelesaikannya dengan path dan nama file, jadi ada skema organisasi logis untuk kita gunakan. Kita dapat memiliki /collections/generic/
folder dengan list
modul di dalamnya.
Konflik Nama : Ini tidak berlaku sama sekali dalam modul eksternal. Dalam sebuah modul, tidak ada alasan yang masuk akal untuk memiliki dua objek dengan nama yang sama. Dari sisi konsumsi, konsumen dari setiap modul yang diberikan dapat memilih nama yang akan mereka gunakan untuk merujuk pada modul, sehingga konflik penamaan yang tidak disengaja tidak mungkin.
Bahkan jika Anda tidak percaya bahwa alasan-alasan itu cukup ditangani oleh bagaimana modul bekerja, "solusi" untuk mencoba menggunakan ruang nama dalam modul eksternal bahkan tidak berfungsi.
Kotak dalam Kotak dalam Kotak
Cerita:
Temanmu Bob memanggilmu. "Saya memiliki skema organisasi baru yang hebat di rumah saya", katanya, "lihatlah!". Rapi, mari kita lihat apa yang muncul Bob.
Anda mulai di dapur dan membuka dapur. Ada 60 kotak berbeda, masing-masing berlabel "Pantry". Anda memilih kotak secara acak dan membukanya. Di dalamnya ada satu kotak berlabel "Grains". Anda membuka kotak "Grains" dan menemukan satu kotak berlabel "Pasta". Anda membuka kotak "Pasta" dan menemukan satu kotak berlabel "Penne". Anda membuka kotak ini dan menemukan, seperti yang Anda harapkan, sekantong pasta penne.
Sedikit bingung, Anda mengambil kotak yang berdekatan, juga berlabel "Pantry". Di dalamnya ada satu kotak, sekali lagi berlabel "Grains". Anda membuka kotak "Grains" dan, sekali lagi, temukan satu kotak berlabel "Pasta". Anda membuka kotak "Pasta" dan menemukan satu kotak, yang ini diberi label "Rigatoni". Anda membuka kotak ini dan menemukan ... sekantong pasta rigatoni.
"Itu bagus!" kata Bob. "Semuanya ada dalam ruang nama!".
"Tapi Bob ..." jawabmu. "Skema organisasi Anda tidak berguna. Anda harus membuka banyak kotak untuk mencapai apa pun, dan sebenarnya tidak ada yang lebih nyaman untuk menemukan apa pun daripada jika Anda hanya meletakkan semuanya dalam satu kotak daripada tiga . Bahkan, karena Anda pantry sudah diurutkan dari rak ke rak, Anda tidak perlu kotak sama sekali. Mengapa tidak hanya meletakkan pasta di rak dan mengambilnya saat Anda membutuhkannya? "
"Kamu tidak mengerti - aku harus memastikan bahwa tidak ada orang lain yang memasukkan sesuatu yang tidak termasuk dalam ruang nama 'Pantry'. Dan aku telah dengan aman mengatur semua pastaku ke dalam Pantry.Grains.Pasta
ruang nama sehingga aku dapat dengan mudah menemukannya"
Bob adalah pria yang sangat bingung.
Modul adalah Kotaknya Sendiri
Anda mungkin pernah mengalami hal serupa terjadi dalam kehidupan nyata: Anda memesan beberapa hal di Amazon, dan setiap item muncul di kotaknya sendiri, dengan kotak yang lebih kecil di dalamnya, dengan barang Anda dibungkus dalam kemasannya sendiri. Bahkan jika kotak interiornya serupa, pengirimannya tidak bermanfaat "digabungkan".
Sesuai dengan analogi kotak, pengamatan utama adalah bahwa modul eksternal adalah kotak mereka sendiri . Ini mungkin item yang sangat kompleks dengan banyak fungsi, tetapi modul eksternal yang diberikan adalah kotaknya sendiri.
Panduan untuk Modul Eksternal
Sekarang kita sudah tahu bahwa kita tidak perlu menggunakan 'ruang nama', bagaimana kita mengatur modul kita? Beberapa prinsip dan contoh panduan mengikuti.
Ekspor sedekat mungkin ke tingkat atas
- Jika Anda hanya mengekspor satu kelas atau fungsi, gunakan
export default
:
MyClass.ts
export default class SomeType {
constructor() { ... }
}
MyFunc.ts
function getThing() { return 'thing'; }
export default getThing;
Konsumsi
import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());
Ini optimal untuk konsumen. Mereka dapat memberi nama tipe Anda apa pun yang mereka inginkan ( t
dalam hal ini) dan tidak perlu melakukan titik-titik asing untuk menemukan objek Anda.
- Jika Anda mengekspor banyak objek, letakkan semuanya di tingkat atas:
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Konsumsi
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
- Jika Anda mengekspor sejumlah besar hal, hanya maka Anda harus menggunakan
module
/ namespace
kata kunci:
MyLargeModule.ts
export namespace Animals {
export class Dog { ... }
export class Cat { ... }
}
export namespace Plants {
export class Tree { ... }
}
Konsumsi
import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();
Bendera merah
Semua yang berikut ini adalah tanda merah untuk penataan modul. Periksa ulang apakah Anda tidak mencoba untuk namespace modul eksternal Anda jika salah satu dari ini berlaku untuk file Anda:
- File yang hanya memiliki deklarasi tingkat atas
export module Foo { ... }
(hapus Foo
dan pindahkan semuanya ke tingkat atas)
- File yang memiliki satu
export class
atau export function
tidakexport default
- Banyak file yang memiliki tingkat yang sama
export module Foo {
di atas (jangan berpikir bahwa ini akan digabungkan menjadi satu Foo
!)
Tidak ada yang salah dengan jawaban Ryan, tetapi bagi orang-orang yang datang ke sini mencari cara mempertahankan struktur satu kelas per file saat masih menggunakan ruang nama ES6 dengan benar, silakan merujuk ke sumber yang membantu ini dari Microsoft.
Satu hal yang tidak jelas bagi saya setelah membaca dokumen adalah: cara mengimpor seluruh modul (digabung) dengan satu
import
.Edit Circling kembali untuk memperbarui jawaban ini. Beberapa pendekatan untuk namespacing muncul di TS.
Semua kelas modul dalam satu file.
Impor file ke dalam namespace, dan tetapkan kembali
Barel
Pertimbangan terakhir. Anda bisa namespace setiap file
Tetapi ketika seseorang mengimpor dua kelas dari namespace yang sama, TS akan mengeluh ada pengidentifikasi duplikat. Satu-satunya solusi saat ini adalah menggunakan alias namespace.
Alias ini benar-benar menjijikkan, jadi jangan lakukan itu. Anda lebih baik dengan pendekatan di atas. Secara pribadi, saya lebih suka 'tong'.
sumber
const fs = require('fs')
,fs
adalah namespace.import * as moment from 'moment'
,moment
adalah namespace. Ini ontologi, bukan spesifikasinya.require
contoh ini tidak berlaku untuk mereka karena sejumlah alasan, termasuk bahwa ruang nama ES6 mungkin tidak dipanggil, sementararequire
mengembalikan objek polos yang mungkin dapat dipanggil.Cobalah mengatur berdasarkan folder:
baseTypes.ts
dog.ts
tree.ts
LivingThings.ts
main.ts
Idenya adalah bahwa modul Anda sendiri seharusnya tidak peduli / tahu mereka berpartisipasi dalam namespace, tetapi ini memaparkan API Anda kepada konsumen dengan cara yang ringkas dan masuk akal yang agnostik terhadap jenis sistem modul yang Anda gunakan untuk proyek tersebut.
sumber
tree.ts
ketika tidak memiliki anggota yang diekspor sama sekali?import
danrequire
bersama dalam satu pernyataan.Peningkatan kecil dari jawaban Albinofrenchy:
base.ts
dog.ts
hal
main.ts
sumber
OP Aku bersamamu kawan. lagi juga, tidak ada yang salah dengan jawaban itu dengan 300 suara lebih, tetapi pendapat saya adalah:
apa yang salah dengan menempatkan kelas ke dalam file mereka sendiri yang hangat dan nyaman secara individual? Maksud saya ini akan membuat segalanya terlihat jauh lebih baik bukan? (atau seseorang seperti file 1000 baris untuk semua model)
jadi, jika yang pertama akan tercapai, kita harus mengimpor impor impor ... impor hanya di masing-masing file model seperti man, srsly, file model, file .d.ts, mengapa ada begitu banyak * ada di sana? itu harus sederhana, rapi, dan hanya itu. Mengapa saya perlu impor di sana? Mengapa? C # mendapat ruang nama karena suatu alasan.
Dan saat itu, Anda benar-benar menggunakan "filenames.ts" sebagai pengidentifikasi. Sebagai pengidentifikasi ... Ayo tahun 2017 sekarang dan kami masih melakukannya? Ima kembali ke Mars dan tidur selama 1000 tahun lagi.
Sedihnya, jawaban saya adalah: tidak, Anda tidak dapat membuat fungsi "namespace" berfungsi jika Anda tidak menggunakan semua impor itu atau menggunakan nama file tersebut sebagai pengidentifikasi (yang menurut saya sangat konyol). Opsi lain adalah: masukkan semua dependensi itu ke dalam kotak bernama filenameasidentifier.ts dan gunakan
bungkus mereka sehingga mereka tidak akan mencoba mengakses kelas lain dengan nama yang sama ketika mereka hanya mencoba untuk mendapatkan referensi dari kelas yang berada tepat di atas mereka.
sumber
Beberapa pertanyaan / komentar yang saya lihat di sekitar subjek ini terdengar bagi saya seolah-olah orang itu menggunakan apa yang
Namespace
mereka maksud dengan 'modul alias'. Seperti yang disebutkan Ryan Cavanaugh dalam salah satu komentarnya, Anda dapat memiliki modul 'Wrapper' yang mengekspor kembali beberapa modul.Jika Anda benar-benar ingin mengimpor semuanya dari nama / alias modul yang sama, gabungkan modul pembungkus dengan pemetaan jalur di
tsconfig.json
.Contoh:
./path/to/CompanyName.Products/Foo.ts
./path/to/CompanyName.Products/Bar.ts
./path/to/CompanyName.Products/index.ts
tsconfig.json
main.ts
Catatan : Resolusi modul dalam file .js keluaran perlu ditangani entah bagaimana, seperti dengan https://github.com/tleunen/babel-plugin-module-resolver ini
Contoh
.babelrc
untuk menangani resolusi alias:sumber
Coba modul ruang nama ini
namespaceModuleFile.ts
bookTreeCombine.ts
--- kompilasi bagian ---
sumber
dog.ts
tree.ts
sumber
Cara yang tepat untuk mengatur kode Anda adalah dengan menggunakan direktori terpisah sebagai ganti ruang nama. Setiap kelas akan berada di file itu sendiri, di folder namespace masing-masing. index.ts hanya akan mengekspor kembali setiap file; tidak ada kode aktual yang harus ada dalam file index.ts. Pengorganisasian kode Anda seperti ini memudahkan navigasi, dan mendokumentasikan diri sendiri berdasarkan pada struktur direktori.
Anda kemudian akan menggunakannya seperti itu:
sumber