Перейти к содержанию

Пространства имен (namespace) и модули (module)

Поскольку на данный момент времени применение данных механизма не имеет смысла, то данную главу стоит изучить только в качестве исторической справки или при возникновении вопросов при работе с устаревшим кодом.

Namespace и module — предназначение

Начать рассмотрение механизмов пространства имен и модулей стоит с уточнения области их применения. Эти механизмы не предназначены для масштабных приложений, которые должны строится при помощи модулей и загружаться с применением модульных загрузчиков. В настоящее время их можно использовать при написании небольших скриптов, внедряемых непосредственно в html страницу при помощи тега <script>, либо в приложениях, которые по каким-либо причинам не могут использовать модульную систему.

Namespace - определение

Пространство имен — это конструкция, которая объявляется при помощи ключевого слова namespace и представляется в коде обычным JavaScript объектом.

namespace Identifier {}

Механизм пространства имен является решением такой проблемы, как коллизии в глобальном пространстве имен, дошедшего до наших дней из тех времён, когда ещё в спецификации ECMAScript не было определено такое понятие, как модули. Простыми словами пространства имен — это совокупность обычной глобальной переменной и безымянного функционального выражения.

Объявленные внутри пространства имен конструкции срываются в безымянном функциональном выражении. Видимые снаружи конструкции записываются в объект, ссылка на который была сохранена в глобальную переменную переданную в качестве аргумента. Что записывать в глобальный объект, а что нет, компилятору указывают при помощи ключевого слова export, о котором речь пойдет совсем скоро.

// @info: До компиляции

namespace NamespaceIdentifier {
  class PrivateClassIdentifier {}
  export class PublicClassIdentifier {}
}
// @info: После компиляции

var NamespaceIdentifier;

(function (NamespaceIdentifier) {
  class PrivateClassIdentifier {}
  class PublicClassIdentifier {}

  NamespaceIdentifier.PublicClassIdentifier = PublicClassIdentifier;
})(NamespaceIdentifier || (NamespaceIdentifier = {}));

Также стоит добавить, что namespace является глобальным объявлением. Это дословно означает, что пространство имен, объявленное как глобальное, не нуждается в экспортировании и импортировании, а ссылка на него доступна в любой точке программы.

Модули (export, import) — определение

Модули в TypeScript определяются с помощью ключевых слов export/import и представляют механизм определения связей между модулями. Данный механизм является внутренним исключительно для TypeScript и не имеет никакого отношения к модулям es2015. В остальном они идентичны es2015 модулям, за исключением определения модуля по умолчанию (export default).

// Файл declaration.ts

export type T1 = {};

export class T2 {}
export class T3 {}

export interface IT4 {}

export function f1() {}

export const v1 = 'v1';
export let v2 = 'v2';
export var v3 = 'v3';
Файл index.ts


import {T2} from './declaration';
import * as declaratios from './declaration';

Кроме того, объявить с использованием ключевого слова export можно даже namespace. Это ограничит его глобальную область видимости и его использование в других файлах станет возможным только после явного импортирования.

// Файл declaration.ts

export namespace Bird {
  export class Raven {}
  export class Owl {}
}
// Файл index.ts

import { Bird } from './declaration';

const birdAll = [Bird.Raven, Bird.Owl];

Необходимо отметить, что экспортировать namespace стоит только тогда, когда он объявлен в теле другого namespace, но при этом до него нужно добраться из программы.

namespace NS1 {
  export namespace NS2 {
    export class T1 {}
  }
}

Конфигурирование проекта

Для закрепления пройденного будет не лишним взглянуть на конфигурирование минимального проекта.

// @info: Структура проекта

* /
   * dest
   * src
      * Raven.ts
      * Owl.ts
      * index.ts
   * package.json
   * tsconfig.json
// @filename: Raven.ts

namespace Bird {
  export class Owl {}
}
// @falename: Owl.ts

namespace Bird {
  export class Raven {}
}
// @filename: index.ts

namespace App {
  const { Raven, Owl } = Bird;

  const birdAll = [Raven, Owl];

  birdAll.forEach((item) => console.log(item));
}
// @filename: tsconfig.json


{
  "compilerOptions": {
      "target": "es2015",
      "module": "none",
      "rootDir": "./src",
      "outFile": "./dest/index.bundle.js"
  }
}
// @filename: package.json


{
"name": "namespaces-and-modules",
"version": "1.0.0",
"description": "training project",
"main": "index.js",
"scripts": {
  "start": "./node_modules/.bin/tsc --watch",
  "build": "./node_modules/.bin/tsc"
},
"author": "",
"license": "ISC",
"devDependencies": {
  "typescript": "^2.5.2"
}
}

Осталось собрать проект, выполнив в консоли следующую команду:

npm run build

Если все было сделано правильно, то в директории dest должен появится файл index.bundle.js.

// @filename: index.bundle.js

var Bird;

(function (Bird) {
  class Owl {}
  Bird.Owl = Owl;
})(Bird || (Bird = {}));

var Bird;

(function (Bird) {
  class Raven {}
  Bird.Raven = Raven;
})(Bird || (Bird = {}));

var App;

(function (App) {
  const { Raven, Owl } = Bird;
  const birdAll = [Raven, Owl];
  birdAll.forEach((item) => console.log(item));
})(App || (App = {}));