o7planning

TypeScript Modules tutorial with Examples

  1. What is a module?
  2. Ideas about modules before ES6
  3. export keyword
  4. import keyword
  5. module/namespace keywords
  6. Using modules in HTML

1. What is a module?

Starting with the ECMAScript 2015 (ES6) specification, JavaScript has a new concept that is module. TypeScript also shares this concept.
Modules with code resources are only used in a closed scope, not in the global scope. This means that variables, functions, classes, .. declared in the module will not be visible to the outside of the module unless they are explicitly exported via the export expression. Also, to use an exported resource of another module you must explicitly import it via the import expression.
Programmers tend to organize each file as a module, which makes it easier to manage code. Although you can define two or more modules in a file with the module or namespace keyword. If a file does not include the module and namespace keywords, that means it is a single module.

2. Ideas about modules before ES6

The idea of a module has been around for a long time in JavaScript, but it wasn't until ES6 (2015) that it was supported at the language level by adding new keywords like import, export, and module. Before the ES6 (2015) version, there were many module specifications created such as CommonJS, AMD, UMD, .. their purpose is to establish conventions about the module ecosystem. Since then, there have been many libraries that implement the above specifications.
A code snippet that creates and uses the module according to CommonJS standards:
// package/lib is a dependency we require
var lib = require( "package/lib" );

// behaviour for our module
function foo(){
    lib.log( "hello world!" );
}
// export (expose) foo to other modules
exports.foo = foo;
Sometimes, old specifications and libraries confuse us, like getting lost in a maze. The following article introduces module history in JavaScript, which helps you get an overview of the module and stay away from learning outdated libraries:

3. export keyword

Similar to JavaScript, TypeScript's code has global scope by default. If you have multiple files in a project, variables, functions, ... written in one file can be recognized and used in other files. For easy understanding, see an example:
file1.ts
var greeting : string = "Hello World!";

function sayHello(name: string) {
    console.log(`Hello $name`);
}
file2.ts
sayHello('Tom');
console.log(greeting);
// Set new value to greeting
greeting = 'Hi';
In the example above, the file1.ts file defines the greeting variable and the sayHello(string) function, which can be recognized and used in the file2.ts file. In addition, the greeting variable can be assigned a new value anywhere in the application, which can lead to conflicts or errors for the application.
export keyword
The export keyword is used to prevent the "default global scope" of TypeScript code. Usage: Put the export keyword in front of the "things" defined at the top-level of the file.
We rewrite the code in file1.ts with the participation of export keyword:
file1.ts (*)
export var greeting : string = "Hello World!";

export function sayHello(name: string) {
    console.log(`Hello $name`);
}
After modifying the code, file1.ts is considered a module.
The compiler will now report an error on file2.ts:
file2.ts (*)
sayHello('Tom');  // ERROR: Cannot find name 'sayHello'.

console.log(greeting);  // ERROR: Cannot find name 'greeting'.
// Set new value to greeting
greeting = 'Hi'; // ERROR: Cannot find name 'greeting'.

4. import keyword

The import keyword is used to import "things" defined with the export keyword of a certain file.
Syntax:
// Import multiple 'things':
import { export_name1, export_name2 } from "file_path_without_extension"

// Import only one 'thing':
import  export_name1 from "file_path_without_extension"

// Import all 'things' into a variable.
import  * as variable_name from "file_path_without_extension"

// Import with alias name:
import { export_name1 as alias_name1, export_name2 } from "file_path_without_extension"
Example:
file1.ts
export var greeting : string = "Hello World!";

export function sayHello(name: string) {
    console.log(`Hello $name`);
}
file2.ts
import {sayHello, greeting} from './file1';

sayHello('Tom');   
console.log(greeting);
Example: Importing all into a variable:
file2b.ts
import * as f1 from './file1';

f1.sayHello('Tom');   
console.log(f1.greeting);
Example: Import with alias name:
file2c.ts
import {sayHello as hello, greeting} from './file1';

hello('Tom');   
console.log(greeting);

5. module/namespace keywords

In JavaScript ES6, the module keyword is used to define a module, this allows you to define multiple modules in a file. TypeScript uses the namespace keyword with similar syntax and purposes.
Note: Both "module" and "namespace" keywords can be used in TypeScript with similar syntax and usage. However, the TypeScript docs discourage the use of the "module" keyword in TypeScript code. It should only be used in JavaScript code.
In TypeScript the "namespace" keyword is slightly stronger than the "module" keyword. You can define a module across multiple files with the "namespace" keyword and use the "--outFile" flag if you want them to be bundled together into a single file at compile time.
In the example below, we define 2 modules in one file.
my_common_libs.ts
export namespace MyMathLib  {
    export function minus(a: number, b: number)  {
        return a - b;
    }
    export function sum(a: number, b: number)  {
        return a + b;
    }
}

export namespace MyStringLib {
    export var LIB_INFO = "String Lib";
    var AUTHOR = 'tran'; // Use only in module.

    export function toUpperCase(s:string)  {
        return s.toUpperCase;
    }
}
In another file, we use the above module.
use_my_common_libs_ex1.ts
import {MyMathLib, MyStringLib} from './my_common_libs';

let value = MyMathLib.minus(1, 2);
console.log(`value = ${value}`);
console.log('MyStringLib info: ' + MyStringLib.LIB_INFO);
See the in-depth article on TypeScript Namespaces:

6. Using modules in HTML

Basically, most modern browsers support modules and have a built-in Module Loader, so we don't have to use any additional libraries. The following code is a way to tell the browser that this JavaScript source is a module:
test.html
<html>
   <head>
      <!-- Important: type='module' -->
      <script type="module" src="./dist/file2.js"></script>
   </head>
   <body>
      <h3>To test, you need to run this file on an HTTP or HTTPS server.
         And see the results on the browser Console.
      </h3>
   </body>
</html>
To successfully test the above example, you must run the test.html file on an HTTP or HTTPS server, and view the results in the browser's Console window.