In the previous chapters you learned how to automate your TypeScript development environment. We also learned how to put into practice type annotations, function, classes and other object oriented programming principles and elements. Modules were deliberately omitted because they deserve their own chapter.

  • Introduction
  • Declaring namespaces & legacy internal modules
  • Importing namespaces & legacy internal modules
  • Running namespace & legacy internal modules
  • Declaring legacy external modules
  • Importing legacy external modules
  • Declaring ES6 modules
  • Importing ES6 modules
  • Declaring AMD modules
  • Importing AMD modules
  • Running AMD modules with Require.js
  • Declaring CommonJS modules
  • Importing CommonJS modules
  • Running CommonJS modules with Browserify
  • Declaring UMD modules
  • Importing UMD modules
  • Running UMD modules
  • Declaring SystemJS modules
  • Importing SystemJS modules
  • Running SystemJS modules with SystemJS
  • Running ES6 modules with webpack

4.1 Introduction

The usage of modules in TypeScript and JavaScript is a topic that often leads to confusion because the module ecosystem is quite extensive: We can declare internal and external modules at design-time using two different module definition syntaxes:

  • Internal (legacy) and namespaces (new).
  • External modules (legacy) and ES6 modules (new). There are more module definition syntaxes at runtime:
  • System
  • AMD
  • CommonJS
  • UMD
  • ES6 There are many available third party module loaders and module bundlers or optimizers:
  • RequireJS
  • SystemJS
  • Browserify
  • Webpack The best way to get out of this confusing landscape is to learn how to use each of the module definition syntaxes and third party module loaders.

You should try to avoid the usage of the module definition syntaxes known as “internal modules” and “external modules” because, they are expected to become legacy in the future as Anders Hejlsberg (creator of TypeScript) expressed when the support of ES6 modules arrive to TypeScript:

As ES6 modules gain adoption, Typescript’s original export-equals and import-equals declarations are expected to become legacy.

As Anders explained we can expect ES6 modules (also known as ECMAScript modules) to become the most widely used module definition syntax as it is the only real proposed standard.

You should try to use external modules over internal modules and namespaces when possible. We will cover how internal modules and namespaces later in this chapter but we can say that internal modules and namespaces were the first implementation of modules in JavaScript and, since they arrived, newer and better approaches have become available.

You can use modules in a JavaScript engine like the one in a web browser or in Node.js but not all the module declaration syntaxes are natively supported by all the environment. For example, Node.js supports CommonJS modules without the need of external module loaders, module bundlers or transpilers.

It is possible to run any kind of modules in any of the available environments, for example it is possible to run AMD modules in Node.js using RequireJS but this not recommended in real world applications because we would be introducing an unnecessary module loader and increasing the level of complexity of the application without additional benefits.

In general, you should use the best module syntax for each environment and try to use a module bundler or optimizer in production environments to boost the performance of your application.

If you are working on a library that will be distributed and used by other developers, you should ensure that your library can be consumed by any of the available module loaders and bundlers.

The following table displays the list of available modules at design time:

Syntax Type Compiles to
Internal modules Internal IIFE
Namespaces Internal IIFE
External modules External AMD, CommonJS, UMD and SystemJS
ES6 modules External AMD, CommonJS, UMD and SystemJS

However, at runtime the following module definitions syntaxes are available:

Syntax Type Node.js Support Browser Support
Namespaces (IIFE) Internal Not Supported Native
AMD External RequireJS RequireJS
CommonJS External Native CommonJS loader
UMD External Native or AMD loader CommonJS or AMD loader
SystemJS External SystemJS loader SystemJS loader
ES6 External Transpiler (Native in the future) Transpiler (Native in the future)

In this chapter we are going to examine each of the available module definition syntaxes and learn how to use some of the most popular module loaders and bundles.

About the companion source code

The companion source code of this chapter includes a library called ndrscr which is inspired by underscore.js. This library is implemented many times using each of the different module definition syntaxes. Each of the examples is located in a different folders and the folder structure should help you to identify the kind of module definition syntax used for the example contained in a particular folder:

The ndrscr library is composed of six files, the root module in the library is located in a file named ndscr.ts. The main module has a dependency on other five modules names arrays, collections, functions, objects and utility.

These modules contain a couple of utility methods each. For example, the arrays module contains methods to select the first or last n items in an array. We will not go into details about the library because it is well documented using comments in the code, we will focus on the modules rather than the code of the library.

├── ndrscr.ts
├── arrays.ts
├── collections.ts
├── functions.ts
├── objects.ts
└── utility.ts

Shiv Kushwaha