Modules in TypeScript

Introduction

In TypeScript, modules provide a way to organize code into separate, reusable files, and to control the visibility of variables, functions, and classes across different files. A module can be either a single file or a directory that contains one or more files, and it can be exported or imported by other modules in the same project.

Exporting a Module

To export a module in TypeScript, you use the export keyword followed by the name of the variable, function, or class you want to export. For example, consider the following file module1.ts:

export const PI = 3.14;

export function square(x: number): number {
  return x * x;
}

export class Circle {
  constructor(public radius: number) {}

  getArea(): number {
    return PI * this.radius * this.radius;
  }
}

In this example, we export a constant PI, a function square(), and a class Circle that calculates the area of a circle given its radius. By exporting these items, we make them available to other modules that import this module.

Importing a Module

To import a module in TypeScript, you use the import keyword followed by the name of the module and the name of the variable, function, or class you want to import. For example, consider the following file module2.ts:

import { PI, square, Circle } from "./module1";

console.log("PI =", PI);
console.log("square(3) =", square(3));

const c = new Circle(5);
console.log("Area of circle with radius 5 =", c.getArea());

In this example, we import the constant PI, the function square(), and the class Circle from the module1.ts file using the curly braces notation. We then use these items in our code to calculate the area of a circle with radius 5.

Exporting Default Modules

In addition to exporting named modules, TypeScript also supports exporting default modules. A default module is a module that exports a single value as its default export, which can be imported using the import keyword without curly braces. For example, consider the following file module3.ts:

const greeting = "Hello, world!";

export default greeting;

In this example, we export a single string value greeting as the default export of this module using the export default syntax. This means that when we import this module in another file, we can import it without curly braces, like this:

import greeting from "./module3";

console.log(greeting); // "Hello, world!"

Exporting and Importing All Modules

Finally, TypeScript also supports exporting and importing all modules in a directory using the * notation. For example, consider the following file module4.ts:

export * from "./module1";

Exporting and Importing All Modules

As I mentioned earlier, TypeScript also supports exporting and importing all modules in a directory using the * notation. This is known as a namespace import, and it allows you to import all the exports from a module into a single namespace. For example, consider the following file module4.ts:

export * from "./module1";

In this example, we export all the named exports from module1.ts using the export * syntax. This means that when we import this module in another file, we can import all the exports from module1.ts like this:

import * as m from "./module4";

console.log("PI =", m.PI);
console.log("square(3) =", m.square(3));

const c = new m.Circle(5);
console.log("Area of circle with radius 5 =", c.getArea());

In this example, we import all the named exports from module4.ts using the * as syntax, which creates a namespace m that contains all the exported items from module1.ts. We can then access these items using the dot notation, like m.PI, m.square(), and m.Circle.

Using Default Exports with Namespace Imports

You can also use default exports in conjunction with namespace imports to import a default export and all named exports from a module into a single namespace. For example, consider the following file module5.ts:

export default function sayHello() {
  console.log("Hello, world!");
}

export const PI = 3.14;

export function square(x: number): number {
  return x * x;
}

export class Circle {
  constructor(public radius: number) {}

  getArea(): number {
    return PI * this.radius * this.radius;
  }
}

In this example, we export a default function sayHello() and several named exports. To import both the default function and the named exports into a single namespace, we can use the following syntax:

import greeting, * as m from "./module5";

greeting();
console.log("PI =", m.PI);
console.log("square(3) =", m.square(3));

const c = new m.Circle(5);
console.log("Area of circle with radius 5 =", c.getArea());

In this example, we import the default function sayHello() using the import greeting syntax, and all the named exports using the * as m syntax. We can then access the default function as greeting() and the named exports as m.PI, m.square(), and m.Circle.

Conclusion

In conclusion, modules in TypeScript provide a way to organize code into reusable, self-contained units that can be easily imported and exported between different files or projects. You can export and import named modules, default modules, or all modules in a directory using a namespace import. By using modules, you can write more maintainable and scalable code in TypeScript.