> Замечание по поводу терминологии: Важно отметить, что в TypeScript 1.5 изменилась номенклатура. "Внутренние модули" теперь называются "пространства имён". "Внешние модули" стали просто "модулями". Это было сделано, чтобы согласовать терминологию с ECMAScript 2015, (а именно: module X {
эквивалентен предпочитаемому в настоящее время namespace X {
).
Table of Contents #
- Введение
- Использование пространств имен
- Использование модулей
- Ошибки при работе с пространствами имен и модулями
Введение #
Данный раздел документации описывает различные пути организации вашего кода в TypeScript с помощью пространств имён и модулей. Мы также затронем несколько сложных вопросов и отметим основные подводные камни, которые могут встретиться при использовании пространств имен и модулей в Typescript.
См. модули для получения более подробной информации о модулях. См. пространства имен для получения более подробной информации о пространствах имен.
Использование пространств имен #
Пространства имен — это просто именованные объекты JavaScript, расположенные в глобальном пространстве имен. И это делает их очень простыми в использовании. Пространства имен могут располагаться в нескольких файлах и могут быть объединены с помощью ключа --outFile
. Они удобны для структурирования кода в веб-приложении, когда все зависимости находятся в тегах <script>
вашей HTML-станицы.
Так же как и в случае замусоривания глобального пространства имён, может оказаться трудно определить зависимости компонентов, особенно в больших приложениях.
Использование модулей #
Аналогично пространствам имен, модули могут содержать и код, и объявления. Основное отличие состоит в том, что модули объявляют свои зависимости.
Модули также зависят от загрузчиков (например CommonJs/Require.js). Для небольшого JS-приложения такой подход может оказаться неоптимальным, но для более крупных решений усилия окупаются модульностью и удобством поддержки. Модули также удобнее с точки зрения повторного использования кода, более сильной изоляции и лучшей поддержки в инструментах создания пакетов.
Также стоит отметить, что для приложений Node.js модули являются основным и рекомендуемым способом структурирования кода.
Начиная с ECMAScript 2015, модули являются неотъемлемой частью языка и должны поддерживаться всеми совместимыми реализациями JavaScript-движков. Таким образом, для новых проектов модули должны быть рекомендуемым способом организации кода.
Ошибки при работе с пространствами имен и модулями #
В этой части описаны основные ловушки, в которые можно попасть при работе с модулями и пространствами имен, а также способы их обхода.
Ссылка (/// <reference>
) на модуль
Часто встречается ошибка, при которой для того, чтобы сослаться на файл модуля, вместо оператора import
используется конструкция /// <reference ... />
. Чтобы разобраться, в чем разница, необходимо сначала понять, как на основе пути, заданного в операторе import
(например: ...
в import x from "...";
, import x = require("...");
, и т.д.) компилятор находит для модуля информацию о типах.
Компилятор попытается найти .ts
, .tsx
, и затем .d.ts
, используя указанный путь. Если определённый файл не может быть найден, компилятор начнёт искать объявления внешних модулей (ambient module declaration). Напомним, что такие модули должны быть объявлены в файле .d.ts
.
-
myModules.d.ts
// В файле .d.ts или в файле .ts, который не является модулем: declare module "SomeModule" { export function fn(): string; }
-
myOtherModule.ts
/// <reference path="myModules.d.ts" /> import * as m from "SomeModule";
Здесь ссылочный тег позволяет найти файл, содержащий объявления внешних модулей. Таким образом подключается файл node.d.ts
, используемый в нескольких примерах использования TypeScript.
Использование пространств имен без необходимости
Если вы переводите программу с пространств имен на модули, в итоге легко прийти к файлу следующего вида:
-
shapes.ts
export namespace Shapes { export class Triangle { /* ... */ } export class Square { /* ... */ } }
В том, что модуль верхнего уровня Shapes
"оборачивает" Triangle
и Square
, нет никакого смысла. Это сбивает с толку и раздражает пользователей вашего модуля:
-
shapeConsumer.ts
import * as shapes from "./shapes"; let t = new shapes.Shapes.Triangle(); // shapes.Shapes?
Ключевой особенностью модулей в TypeScript является то, что в одной области видимости модули никогда не сливаются друг с другом. Поскольку пользователь модуля решает, какое имя ему назначить, нет необходимости заранее заключать экспортируемые элементы в отдельное пространство имен.
Чтобы повторить, почему не следует пытаться заключать содержимое модуля в пространства имен, вспомним, что основной их идеей является обеспечение логической группировки кода и предотвращение конфликтов имен. А модуль сам по себе уже обеспечивает логическую группировку, и его имя верхнего уровня определяется импортирующим кодом, поэтому нет никакой необходимости использовать дополнительный уровень вложенности для экспортируемых из модуля объектов.
Отредактированный пример:
-
shapes.ts
export class Triangle { /* ... */ } export class Square { /* ... */ }
-
shapeConsumer.ts
import * as shapes from "./shapes"; let t = new shapes.Triangle();
Недостатки модулей
Поскольку соотношение между JS-файлами и модулями — один к одному, в TypeScript существует такое же соотношение между исходными и сгенерированными JavaScript-файлами. Это проявляется в том числе в невозможности использовать опцию компилятора --outFile
для соединения нескольких исходных файлов модулей в один JavaScript-файл.
Поддержите перевод документации:
Documentation generated by mdoc.