In this lesson we will see TypeScript modules. Topics on this page (not covered by ES6):
Table of Contents
What are Modules
A module is a collection of small independent units that we can reuse in our application. Using modules makes development easier. Almost every language has a concept of modules — a way to include functionality declared in one file within another. The benefits are:
- Code can be split into smaller files of self-contained functionality (encapsulate behaviour)
- The same modules can be shared across any number of applications.
- Easy to work with
- Easy to maintain the code
- Easy to scale
Before ES6 it was impossible to directly reference or include one JavaScript file in another. The solution was to separate the code into multiple script tags and to use a special design pattern for modules. The pattern uilizes closure and IIFE (see in JavaScript function lesson examples).
>ES6 introduced a module feature, which is inherited by TypeScript. Modules in both languages (JavaScript and TypeScript) are a way to encapsulate code into their own scope. That is, when we create a module and add some code to it, we are not letting anything (like variables, functions, etc.) escape silently. Everything that we want to provide externally needs to be explicitly exported by our module and explicitly imported by other modules/scripts.
In ES6 modules are classified as importing a module and exporting a module.
In Typescript there are two types of modules, internal modules (namespaces) and external modules. The syntax of the latter is equivalent to the ES6 module syntax.
External Modules
This solution is the same for ES6 and TypeScript. Everything inside an ES6 module is private by default, and runs in strict mode (there’s no need for 'use strict'). Public variables, functions and classes are exposed using export.
External modules are compiled separately (per file), and are to be loaded during runtime. There is no top-level module declaration, as a top-level export or import statement itself will instruct the compiler that the file itself is a module, and should be compiled accordingly. For examples in file lib.js:
export class MyClass { }
export const PI = 3.1415926;
export function sum(...args) {
log('sum', args);
return args.reduce((num, tot) => tot + num);
}
export function mult(...args) {
log('mult', args);
return args.reduce((num, tot) => tot * num);
}
// private function
function log(...msg) {
console.log(...msg);
}
A single export can be deined:
export { PI, sum, mult, myClass };
In another file import is then used to pull items from a module into another script or module:
import { sum } from './lib.js';
In this case, lib.js is in the same folder as the file with the import. Absolute file references (starting with /), relative file references (starting ./ or ../) or full URLs can be used.
Multiple items can be imported at one time:
import { sum, mult } from './lib.js';
imports can be aliased to resolve naming collisions:
import { sum as addAll, mult as multiplyAll } from './lib.js';
console.log( addAll(1,2,3,4) ); // 10
console.log( multiplyAll(1,2,3,4) ); // 24
Finally, all public items can be imported by providing a namespace:
import * as lib from './lib.js'; console.log( lib.PI ); // 3.1415926 console.log( lib.add(1,2,3,4) ); // 10 console.log( lib.mult(1,2,3,4) ); // 24
Internal Modules
Internal modules are also called namespaces. Internal modules are used when the module is to be compiled along a project, and are primarily a tool for separation-of-concerns (design principle), like namespaces in C#. When compiled with the TypeScript compiler, internal modules are put into closures (via self-invoking functions). For example:
and for function return type (as in C). The following examples show the syntax of type specification.
namespace MyApp {
export class MyClass { }
}
When the code above is compiled to JavaSCript it becomes:
"use strict";
var MyApp;
(function (MyApp) {
class MyClass {
}
MyApp.MyClass = MyClass;
})(MyApp || (MyApp = {}));