Конфеты Кубок аналогия
Версия 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
!)
Ничего плохого в ответе Райана, но для тех, кто пришел сюда и ищет, как сохранить структуру « один класс на файл» при правильном использовании пространств имен ES6, обратитесь к этому полезному ресурсу от Microsoft.
После прочтения документа мне неясно, как импортировать весь (объединенный) модуль с одним
import
.Отредактируйте по кругу, чтобы обновить этот ответ. В TS появилось несколько подходов к пространству имен.
Все классы модулей в одном файле.
Импортировать файлы в пространство имен и переназначить
баррели
Окончательное рассмотрение. Вы могли бы пространство имен каждого файла
Но так как один импортирует два класса из одного пространства имен, TS будет жаловаться, что есть дублирующий идентификатор. Единственное решение на этот раз состоит в том, чтобы затем создать псевдоним пространства имен.
Этот псевдоним абсолютно отвратителен, поэтому не делайте этого. Вам лучше с подходом выше. Лично я предпочитаю «бочку».
источник
const fs = require('fs')
,fs
это пространство имен.import * as moment from 'moment'
,moment
это пространство имен. Это онтология, а не спецификация.require
пример не применяется к ним по ряду причин, включая то, что пространства имен ES6 не могут быть вызваны, в то время какrequire
возвращает простой объект, который вполне может быть вызван.Попробуйте организовать по папке:
baseTypes.ts
dog.ts
tree.ts
LivingThings.ts
main.ts
Идея состоит в том, что ваш модуль сам не должен заботиться / знать, что он участвует в пространстве имен, но это предоставляет вашему API потребителю компактный, разумный способ, который не зависит от того, какой тип модульной системы вы используете для проекта.
источник
tree.ts
когда у него вообще нет экспортируемого члена?import
иrequire
вместе в одном утверждении.Небольшое наложение альбинофренчего ответа:
base.ts
dog.ts
things.ts
main.ts
источник
OP Я с тобой, парень. опять же, нет ничего плохого в этом ответе с 300+ голосами "за", но мое мнение таково:
что плохого в том, чтобы помещать занятия в свои уютные теплые файлы индивидуально? Я имею в виду, что это заставит вещи выглядеть намного лучше, верно? (или кто-то просто как 1000-строчный файл для всех моделей)
Итак, если первое будет достигнуто, мы должны импортировать import import ... import только в каждый из файлов модели, таких как man, srsly, файл модели, файл .d.ts, почему их так много * там? все должно быть просто, аккуратно и все. Зачем мне там импорт? Зачем? C # получил пространства имен по причине.
И к тому времени вы буквально используете «filenames.ts» в качестве идентификаторов. Как идентификаторы ... Давай его 2017 сейчас, и мы все еще делаем это? Има возвращается на Марс и спит еще 1000 лет.
К сожалению, мой ответ: нет, вы не можете сделать функционал «пространства имен» функциональным, если вы не используете все эти операции импорта или не используете эти имена файлов в качестве идентификаторов (что я считаю действительно глупым). Другой вариант: поместите все эти зависимости в блок с именем filenameasidentifier.ts и используйте
оберните их так, чтобы они не пытались получить доступ к другим классам с тем же именем, когда они просто пытаются получить ссылку из класса, расположенного прямо над ними.
источник
Некоторые из вопросов / комментариев, которые я видел по этой теме, звучат для меня так, как будто человек использует то,
Namespace
что означает «псевдоним модуля». Как упоминал Райан Кавано в одном из своих комментариев, у вас может быть модуль Wrapper для реэкспорта нескольких модулей.Если вы действительно хотите импортировать все это из одного и того же имени модуля / псевдонима, объедините модуль-обертку с отображением путей в вашем
tsconfig.json
.Пример:
./path/to/CompanyName.Products/Foo.ts
./path/to/CompanyName.Products/Bar.ts
./path/to/CompanyName.Products/index.ts
tsconfig.json
main.ts
Примечание . Разрешение модуля в выходных файлах .js необходимо будет каким-то образом обработать, например, с помощью этого https://github.com/tleunen/babel-plugin-module-resolver.
Пример
.babelrc
для обработки разрешения псевдонима:источник
Попробуйте этот модуль пространств имен
namespaceModuleFile.ts
bookTreeCombine.ts
--- часть компиляции ---
источник
dog.ts
tree.ts
источник
Правильный способ организовать ваш код - использовать отдельные каталоги вместо пространств имен. Каждый класс будет в своем собственном файле, в соответствующей папке пространства имен. index.ts будет только реэкспортировать каждый файл; фактический код не должен быть в файле index.ts. Подобная организация вашего кода значительно упрощает навигацию и самодокументируется на основе структуры каталогов.
Затем вы бы использовали его как таковой:
источник