Module vs Namespace-Import vs Require Typescript
Я получаю много путаницы с module/namespace/export и import, require, reference использование.
Будучи из Java фона, может кто-нибудь объяснить мне в двух словах, когда использовать то, что и что такое правильный дизайн? Я чувствую, что я испортил, когда я пишу образец проекта
пока это мое понимание
1. module для внешних пакетов
2. namespace для внутренних пакетов
- Я не понял, как мы их классифицируем?
- когда экспортировать класс или пространство имен или посылка?
- если мы экспортируем пакет / пространство имен, все классы внутри которого экспортируются или должны быть явно экспортированы
- как каждый из них может быть импортирован/требуется?
согласно doc, если я создаю каждый файл " ts "для каждого менеджера/модели, Typescript не рекомендует использовать"пространства имен"? Напрямую использовать ссылки?
пожалуйста, объясните подробно, как я исхожу из другого фона и не уверен ES6 / ES5 etc'.
Я видел, как несколько человек поднимают / путаются с одними и теми же вопросами. Я надеюсь, что кто-то может объяснить подробно с реальным сценарием мира
4 ответов:
Я не понял, как мы их классифицируем?
пространства имен используются для организации / инкапсуляции кода. Внешние модули используются для организации / инкапсуляции кода и поиска кода во время выполнения. На практике у вас есть два варианта во время выполнения: 1) объединить весь транспилированный код в один файл или 2) использовать внешние модули и иметь несколько файлов и требовать какого-либо другого механизма для получения этих файлов.
когда экспортировать класс или пространство имен или посылка?
чтобы сделать тип или значение видимым за пределами файла, в котором он находится, Вы должны экспортировать его, если он находится внутри пространства имен. Независимо от того, экспортируете ли вы его на верхнем уровне или в пространстве имен, будет решено, находится ли он теперь во внешнем модуле.
если мы экспортируем пакет / пространство имен, все классы внутри которого экспортируются или должны быть явно экспортированы
классы в пространстве имен всегда должны быть явно экспортированы для класса быть виден во время компиляции вне файла, в котором он определен.
как каждый из них может быть импортирован/требуется?
это зависит от того, используете ли вы внешние модули. Внешний модуль всегда нужно будет импортировать, чтобы "использовать" его. Импорт пространства имен, которое не находится во внешнем модуле, на самом деле просто предоставляет псевдоним для пространства имен-вам все равно нужно префикс type/whatever с псевдонимом (и именно поэтому вы обычно не хотите использование пространств имен с внешними модулями; это означает, что вы всегда должны использовать префикс при обращении к любым внешним модулем.) Пространства имен, которые не находятся во внешнем модуле, могут охватывать файлы, поэтому, если вы находитесь в том же пространстве имен, вы можете ссылаться на все, что экспортируется пространством имен, без необходимости какого-либо импорта.
чтобы действительно понять вышеизложенное, вам нужны некоторые фоновые знания. Главное, что нужно понять со ссылками / пространствами имен / внешними модулями, это то, что они конструкции делают во время компиляции и то, что они делают во время выполнения.
справочная директивы используются во время компиляции, чтобы найти информацию о типе. В вашем источнике есть определенный символ. Как компилятор TypeScript находит определение для этого символа? Справочная директива в значительной степени была включена в tsconfig.механизм json -- использование tsconfig.json, вы говорите компилятору, где находятся все ваши источники.
пространства имен могут содержать определения типов и/или реализация. Если пространство имен содержит только информацию о типе, то оно вообще не имеет проявления времени выполнения - вы можете проверить это, посмотрев на вывод JS и найдя пустой файл JS. Если пространство имен имеет код реализации, то код заключен в замыкание, которое назначается глобальной переменной с тем же именем, что и пространство имен. С вложенными пространствами имен, будет глобальная переменная для корневого пространства имен. Опять же, проверьте вывод в JS. Пространства имен исторически таковы, как JS на стороне клиента библиотеки попытались избежать проблемы с коллизиями имен. Идея состоит в том, чтобы обернуть всю библиотеку в одно закрытие, а затем выставить как можно меньше глобального следа-только одну глобальную переменную, ссылающуюся на закрытие. Ну, проблема все еще в том, что вы претендовали на имя в глобальном пространстве. Что, если вы хотите, скажем, две версии библиотеки? Пространство имен TypeScript по-прежнему имеет вопрос о том, как найти источник для пространства имен. То есть исходный код, который ссылается на A. B все еще имеет проблему с сообщением компилятору, как найти A. B -- либо с помощью ссылочных директив, либо с помощью tsconfig.формат JSON. Или поместив пространство имен во внешний модуль, а затем импортировав внешний модуль.
внешние модули, созданные на стороне сервера JS. Существует взаимно однозначное соответствие между внешним модулем и файлом в файловой системе. Структуру каталогов файловой системы можно использовать для организации внешних модулей во вложенную структуру. Импорт внешний модуль, как правило, всегда вводит зависимость времени выполнения от этого внешнего модуля (исключение-когда вы импортируете внешний модуль, но затем не используете его экспорт в позиции значения-то есть вы импортируете только внешний модуль, чтобы получить информацию о его типе). Внешний модуль неявно находится в замыкании, и это ключ: пользователь модуля может назначить замыкание любой локальной переменной, которую они хотят. TypeScript / ES6 добавляет дополнительный синтаксис вокруг сопоставления экспорта из внешних модулей к локальным именам, но это просто тонкость. На стороне сервера поиск внешнего модуля относительно прост: просто найдите файл, представляющий внешний модуль в локальной файловой системе. Если вы хотите использовать внешние модули на стороне клиента, в браузере, это становится более сложным, поскольку нет эквивалента файловой системе, которая имеет модуль, доступный для загрузки. Итак, теперь на стороне клиента вам нужен способ объединить все эти файлы в форму, которая может быть используется удаленно в браузере - вот где модули bundlers, такие как Webpack (Webpack делает намного больше, чем модули bundle, хотя) и Browserify вступают в игру. Пакетов, модуль разрешения времени выполнения внешних модулей в браузере.
сценарий реального мира: AngularJS. Притворитесь, что внешние модули не существуют, используйте одно пространство имен для ограничения загрязнения глобального пространства (в приведенном ниже примере одна переменная MyApp-это все, что есть в глобальном пространстве), только экспорт интерфейсы и использование AngularJS dependency-injection для обеспечения доступности реализаций для использования. Поместите все классы в корень каталога, добавьте tsconfig.json в корень, установите AngularJS typings в том же корневом каталоге, чтобы tsconfig.json тоже поднимает его, объединяет все выходные данные в один JS-файл. Это будет отлично работать для большинства проектов, если повторное использование кода не вызывает особых проблем.
MyService.ТС:
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.ТС:
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); }использование IIFE, чтобы избежать загрязнять глобальную область видимости во время выполнения. В этом примере глобальные переменные вообще не создаются. (A tsconfig.предполагается, что json.)
Фу.ТС:
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 })();бар.ТС:
// 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, вы можете исключить введение MyApp в качестве глобальной переменной в первом примере.
MyService.ТС:
interface MyService { .... } (function() { class MyServiceImpl implements MyService { } angular.module("MyApp").service("myService", MyServiceImpl); })();MyController.ТС:
(function() { class MyController { constructor(private myService: MyService) { } } angular.module("MyApp").controller("myController", MyController); })();
есть две вещи:
- A модуль в TypeScript является стандартным понятием ES6, он использует
import/exportключевые слова на верхнем уровне настоящего Кодекса;- A пространство имен это понятие, специфичное для TypeScript, чтобы помочь организовать код устаревшим способом.
пространства имен
это почти устаревшее понятие. До модулей ES6 общий способ разделения JavaScript код в браузере должен был создавать глобальные переменные. Например, все функции API, такие как подчеркивание был расположен в глобальной переменной с именем
_.этот старый способ продолжения похож на пакеты Java или пространства имен PHP. Он не адаптирован к сети. Новый стандарт ECMAScript решает такие проблемы, как: как использовать две библиотеки с одинаковым именем? Как использовать две разные версии одной и той же библиотеки?
Примечание: в версиях TypeScript до определения ECMAScript " модулей "(лето 2014 года) пространства имен назывались" внутренними модулями", а модули - "внешними модулями".
примечание 2: ключевое слово
exportвнутриnamespace- это нестандартное использование ключевого слова TypeScript. Это значит объявить, что доступны из-за пределов пространства имен.модули ES6
модуль-это файл, содержащий ключевые слова
importилиexportat верхний уровень кода.TypeScript следует стандарту из ECMAScript. Предлагаю почитать хорошее введение в модули ES6 в статье из Mozilla.
если вы хотите использовать модули в интерфейсном приложении (в браузере), то вам придется использовать bundler (Webpack [документация здесь], Browserify) или погрузчиком (SystemJS [учебник здесь], RequireJS) и настроить TypeScript с этой средой.
если ваш код выполняется в узле.js, просто настройте компилятор TypeScript для создания формата CommonJS.
Примечание: пространство имен может быть объявлено в модуле. В этом случае он не будет доступен как глобальная переменная из-за пределов модуля. Однако, его можно экспортировать из модуля.
- модуль для внешних пакетов 2. пространство имен предназначено для внутренних пакетов
на самом деле
moduleключевое слово было замененоnamespaceключевое слово.лучшее утверждение таким образом модули это то, что раньше называлось внешними модулями,пространство имен это то, что раньше называлось внутренних модулей.
больше
надеюсь, что это поможет в будущем : https://basarat.gitbooks.io/typescript/content/docs/project/modules.html
" require" и "импорт" равнозначны по функциональности. мы можем использовать их оба взаимозаменяемо, потому что у нас есть транспилеры, которые на самом деле не заботятся о том, поддерживает ли браузер их изначально или нет. но, пока" require " имеет свои корни в старом стиле кодирования, начиная с CommonJS еще в 2009 году," импорт " выводит свой синтаксис из широко принятого синтаксиса ES6 (ES2015). поэтому вы должны использовать "импорт" для новых проектов, а не " require".
Comments