Конфеты Кубок аналогия
Версия 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 разных коробок, каждая с надписью «Кладовая». Вы выбираете ящик наугад и открываете его. Внутри находится одна коробка с надписью «Зерна». Вы открываете коробку «Зерна» и находите одну коробку с надписью «Макароны». Вы открываете коробку "Паста" и находите одну коробку с надписью "Пенне". Вы открываете эту коробку и находите, как и ожидалось, пакет с пастой пенне.
Немного растерянно, вы берете соседнюю коробку, также с надписью «Кладовая». Внутри находится одна коробка, снова с надписью «Зерна». Вы открываете коробку «Зерна» и снова находите одну коробку с надписью «Макароны». Вы открываете коробку «Паста» и находите одну коробку, которая помечена как «Ригатони». Вы открываете эту коробку и находите ... пакет с пастой ригатони.
"Здорово!" говорит Боб. «Все в пространстве имен!».
«Но Боб ...» вы отвечаете. «Ваша организационная схема бесполезна. Вы должны открыть кучу коробок, чтобы добраться до чего-либо, и на самом деле найти что-либо более удобно, чем если бы вы просто положили все в одну коробку вместо трех . Фактически, так как ваш кладовая уже отсортирована по полкам, ящики вам вообще не нужны. Почему бы просто не положить макароны на полку и не забрать их, когда они вам понадобятся? "
«Вы не понимаете - мне нужно убедиться, что никто не помещает что-то, что не принадлежит, в пространство имен« Кладовая ». И я благополучно организовал все свои макароны в 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
!)