Аналогія чашки цукерки
Версія 1: Чашка на кожну цукерку
Скажімо, ви написали такий код так:
Mod1.ts
export namespace A {
export class Twix { ... }
}
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Mod3.ts
export namespace A {
export class KitKat { ... }
}
Ви створили цю установку:
Кожен модуль (аркуш паперу) отримує свою власну чашку з назвою A
. Це марно - ви насправді тут не організовуєте свої цукерки, ви просто додаєте додатковий крок (виймаючи його з чашки) між вами та частуваннями.
Версія 2: Одна чашка в глобальному масштабі
Якщо ви не використовували модулі, ви можете написати такий код (зверніть увагу на відсутність export
декларацій):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
Цей код створює об'єднаний простір імен A
у глобальному масштабі:
Ця настройка корисна, але не застосовується у випадку модулів (оскільки модулі не забруднюють глобальну область).
Версія 3: Відходи без зубців
Повертаючись до вихідного наприклад, чашки A
, A
і A
не роблять вам послугу. Натомість ви можете написати код як:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
щоб створити малюнок, який виглядає приблизно так:
Набагато краще!
Тепер, якщо ви все ще думаєте про те, наскільки ви дійсно хочете використовувати простір імен зі своїми модулями, читайте далі ...
Це не ті поняття, які ви шукаєте
Нам потрібно повернутися до витоків того, чому існують простори імен в першу чергу і вивчити, чи мають ці причини сенс для зовнішніх модулів.
Організація : простори імен зручні для групування об'єктів і типів, пов'язаних з логікою. Наприклад, у C # ви знайдете всі типи колекцій у System.Collections
. Організовуючи наші типи в ієрархічні простори імен, ми надаємо хороший досвід «відкриття» для користувачів цих типів.
Конфлікти імен: простори імен важливі, щоб уникнути зіткнення імен. Наприклад, у вас можуть бути My.Application.Customer.AddForm
і My.Application.Order.AddForm
- два типи з однаковим іменем, але іншим простором імен. Мовою, де всі ідентифікатори існують в одній кореневій області та всі збірки завантажують усі типи, важливо, щоб все було в просторі імен.
Чи мають ці причини сенс у зовнішніх модулях?
Організація : Зовнішні модулі вже є у файловій системі. Ми повинні вирішити їх за допомогою шляху та назви файлів, тому існує логічна організаційна схема, яку ми можемо використовувати. У нас може бути /collections/generic/
папка з list
модулем.
Конфлікти імен : це взагалі не стосується зовнішніх модулів. У модулі немає жодної вірогідної причини мати два об'єкти з однаковою назвою. З боку споживання, споживач будь-якого модуля отримує назву, яку він використовуватиме для позначення модуля, тому випадкові конфлікти імен неможливі.
Навіть якщо ви не вірите, що ці причини адекватно вирішені тим, як працюють модулі, "рішення" спроби використання просторів імен у зовнішніх модулях навіть не працює.
Коробки в ящиках в коробках
Історія:
Ваш друг Боб зателефонує вам. "У мене в будинку чудова нова організаційна схема", - каже він, - приходьте перевірити! Акуратно, давайте подивимось, що придумав Боб.
Починаєш на кухні і відкриваєш комору. Є 60 різних ящиків, кожна з яких позначена "комора". Ви вибираєте скриньку навмання і відкриваєте її. Всередині - одна коробка з написом "Зерна". Ви відкриваєте вікно "Зерна" і знаходите одну коробку з написом "Макаронні вироби". Ви відкриваєте вікно "Макаронні вироби" і знаходите одну коробку з написом "Пенне". Ви відкриєте цю скриньку і знайдете, як ви очікуєте, пакетик макаронних виробів Пенне.
Злегка розгублений, ви підбираєте сусідню коробку, також з написом "Комора". Всередині - одна коробка, знову з написом "Зерна". Ви відкриваєте вікно "Зерна" і знову виявляєте одну коробку з написом "Паста". Ви відкриваєте вікно "Макаронні вироби" і знаходите єдину коробку, на цій - "Rigatoni". Ви відкриєте цю скриньку і знайдете ... мішечок з ригатоні макаронами.
"Це чудово!" каже Боб. "Все в просторі імен!".
"Але Боб ...", ти відповідаєш. "Ваша організаційна схема марна. Вам потрібно відкрити купу коробок, щоб дістатися до чого-небудь, і насправді не зручніше щось знайти, ніж якби ви просто помістили все в одну скриньку замість трьох . Насправді, оскільки комора вже сортується по полиці, коробки вам взагалі не потрібні. Чому б просто не встановити макарони на полицю і забрати її, коли вона вам потрібна? "
"Ви не розумієте - мені потрібно переконатися, що ніхто більше не вкладає те, що не належить до простору імен" Комора ". І я безпечно організував усі свої макарони в Pantry.Grains.Pasta
простір імен, щоб я міг легко знайти його"
Боб - дуже заплутана людина.
Модулі є власною коробкою
У вас, напевно, траплялося щось подібне в реальному житті: ви замовляєте кілька речей на Amazon, і кожен предмет відображається у власній коробці, з меншою коробкою всередині, при цьому ваш продукт загорнутий у власну упаковку. Навіть якщо міжкімнатні коробки схожі, вантажі не корисно «поєднуються».
Ідучи з аналогією коробки, головне зауваження полягає в тому, що зовнішні модулі є власною коробкою . Це може бути дуже складний предмет з великою кількістю функціональних можливостей, але будь-який даний зовнішній модуль - це власний ящик.
Керівництво для зовнішніх модулів
Тепер, коли ми зрозуміли, що нам не потрібно використовувати «простори імен», як нам організувати наші модулі? Дотримуються деяких керівних принципів та прикладів.
Експортуйте якомога ближче до верхнього рівня
- Якщо ви експортуєте лише один клас чи функцію, використовуйте
export default
:
MyClass.ts
export default class SomeType {
constructor() { ... }
}
MyFunc.ts
function getThing() { return 'thing'; }
export default getThing;
Споживання
import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());
Це оптимально для споживачів. Вони можуть називати ваш тип, що вони хочуть ( t
у даному випадку), і не потрібно робити сторонні крапки, щоб знайти ваші об’єкти.
- Якщо ви експортуєте кілька об’єктів, поставте їх на найвищий рівень:
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Споживання
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
- Якщо ви експортуєте велику кількість речей, лише тоді ви повинні використовувати
module
/ namespace
ключове слово:
MyLargeModule.ts
export namespace Animals {
export class Dog { ... }
export class Cat { ... }
}
export namespace Plants {
export class Tree { ... }
}
Споживання
import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();
Червоні прапори
Усі нижче наведені червоні прапори для структурування модулів. Двічі перевірте, чи не намагаєтесь ви простору імен зовнішні модулі, якщо будь-який із них застосовується до ваших файлів:
- Файл, єдиним декларацією верхнього рівня якого є
export module Foo { ... }
(видаліть Foo
і перемістіть усе "вгору" на рівень)
- Файл, який має одинарний
export class
або export function
не такийexport default
- Кілька файлів, які мають однакові
export module Foo {
на верхньому рівні (не думайте, що вони збиратимуться в один Foo
!)