Modules & Namespaces: Code Organization

Modules & Namespaces: Code Organization

As your application grows, keeping all your code in one file becomes impossible. TypeScript provides multiple ways to organize and share code across your project, primarily through Modules and Namespaces.


1. ES Modules (The Industry Standard)

TypeScript uses the standard ECMAScript module syntax (import/export). Any file containing a top-level import or export is considered a module.

Named Exports

// math.ts
export const PI = 3.14;
export function add(a: number, b: number) { return a + b; }

// app.ts
import { PI, add } from "./math";

Default Exports

Each file can have exactly one default export.

// Logger.ts
export default class Logger {
    log(msg: string) { console.log(msg); }
}

// app.ts
import MyLogger from "./Logger"; // You can name it anything

2. Barrel Exports (Re-exporting)

To simplify imports, you can create an index.ts file in a folder that re-exports everything from that folder. This is known as a Barrel.

// components/index.ts
export * from "./Button";
export * from "./Input";
export { default as Header } from "./Header";

// app.ts
import { Button, Input, Header } from "./components";

3. Namespaces (Internal Modules)

Namespaces were common in older TypeScript versions to group related code and avoid global scope pollution. In modern development, ES Modules are preferred, but Namespaces are still useful for legacy code or specific structural needs.

namespace Validation {
    export interface StringValidator {
        isValid(s: string): boolean;
    }

    export const numberRegexp = /^[0-9]+$/;
}

let validator: Validation.StringValidator;

4. Ambient Modules and .d.ts Files

Sometimes you use libraries that are written in plain JavaScript. To use them in TypeScript, you need a Declaration File (.d.ts). These files contain only type information and no implementation code.

Using @types

Most popular libraries have community-maintained types.

npm install --save-dev @types/lodash

Writing Your Own

If a library has no types, you can declare it yourself:

// global.d.ts
declare module "my-old-library" {
    export function doSomething(n: number): void;
}

5. Module Resolution Strategies

TypeScript has a sophisticated system for finding files.

  • Relative Imports: ./utils, ../types.
  • Non-relative Imports: react, lodash. TypeScript looks in node_modules.

Pro-Tip: You can configure Path Aliases in tsconfig.json to avoid ugly imports like ../../../utils.

"paths": {
  "@utils/*": ["src/utils/*"]
}

6. Summary

  • ES Modules are the standard for modern JS/TS.
  • Barrels keep your import lists clean.
  • Namespaces are for internal organization or legacy support.
  • Declaration files bridge the gap between TS and JS libraries.