TypeScript

Modules in TypeScript: A Comprehensive Guide

A module is a file that exports things other files can import. That's it. No magic.

23 Apr 2024

Modules in TypeScript: A Comprehensive Guide

A module is a file that exports things other files can import. That's it. No magic.

In TypeScript, any file with a top-level import or export is treated as a module. Files without them are treated as global scripts.

The old way: namespaces

TypeScript originally used the module keyword (later renamed to namespace) to group code:

Typescript
namespace MyModule {
  export function sayHello(name: string) {
    console.log(`Hello, ${name}!`);
  }
}

This still works, but it's a legacy pattern. Modern TypeScript uses ES modules.

The modern way: ES modules

Export from one file, import in another:

Typescript
// greet.ts
export function sayHello(name: string) {
  console.log(`Hello, ${name}!`);
}

// app.ts
import { sayHello } from './greet';
sayHello('John');

Each file is its own scope. Nothing leaks out unless you explicitly export it.

The trade-off

Modules give you encapsulation, clear dependency graphs, and tree-shaking. You can see exactly what each file depends on.

The cost: module resolution can be confusing. TypeScript has moduleResolution: "node", "node16", "bundler" — each with different rules about file extensions, package.json exports, and .js vs .ts imports. Getting the tsconfig.json right is half the battle.

My advice: use ES modules. Set "module": "esnext" and "moduleResolution": "bundler" if you're using a bundler. Forget namespaces unless you're maintaining legacy code.