100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
TypeScript

Modules in TypeScript

How TypeScript uses ES module syntax (import/export) to organize code across files, with type-only imports and module resolution basics.

Modules & ToolingIntermediate12 min readJul 8, 2026
Analogies

1. Introduction

A module in TypeScript is any file that contains a top-level import or export statement. Modules let you split a program into independent, reusable pieces, each with its own scope, so identifiers declared in one file do not leak into another unless explicitly exported and imported. TypeScript builds directly on the ECMAScript (ES) module syntax standardized in JavaScript, while adding type-aware features such as type-only imports/exports and compile-time checking of what a module exposes.

🏏

Cricket analogy: A TypeScript module is like a single team's dressing room: players (variables) declared inside stay private to that team unless the captain explicitly "exports" them onto the team sheet for other squads to "import" and select.

Before ES modules were standardized, TypeScript supported its own module systems (CommonJS, AMD, UMD, SystemJS) via the module compiler option, and it still emits code targeting these formats when needed for Node.js or bundlers. Understanding modules is essential for any real-world TypeScript project because virtually all modern codebases are organized as a graph of import/export relationships.

🏏

Cricket analogy: Before the ICC standardized T20 rules globally, boards ran their own domestic formats like the old Ranji knockout structure; similarly TypeScript's module option can still emit CommonJS or AMD for older Node/bundler leagues even though ES modules are now the standard format everyone plays by.

2. Syntax

typescript
// mathUtils.ts — exporting
export const PI = 3.14159;

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

export interface Point {
  x: number;
  y: number;
}

export default class Calculator {
  add(a: number, b: number): number {
    return a + b;
  }
}

// app.ts — importing
import Calculator, { PI, square, Point } from "./mathUtils";
import type { Point as PointType } from "./mathUtils"; // type-only import
import * as MathUtils from "./mathUtils"; // namespace-style import of all exports

const calc = new Calculator();
console.log(calc.add(2, 3), PI, square(4));

3. Explanation

ES modules (import/export) are the modern standard for organizing TypeScript and JavaScript code, and TypeScript's compiler understands them natively. A file can have multiple named exports (export const, export function, export interface) and at most one default export. Named exports are imported with matching names inside { }, while a default export is imported without braces under any local name you choose. The import * as Name form collects every export of a module into a single namespace object, which is useful when a module has many related exports.

🏏

Cricket analogy: A module with named exports like export const strikeRate and export function economyRate mirrors a scorecard with multiple named stats you import individually, while a single export default battingOrder is like the one headline stat pulled in under any name; import * as Stats from "./match" collects the whole scorecard into one namespace object.

TypeScript also supports import type and export type, which are erased entirely at compile time — they exist only to communicate to the compiler (and to bundlers using isolatedModules) that the imported symbol is a type, not a runtime value. This matters because mixing type and value imports carelessly can cause runtime errors when a bundler tries to resolve a type-only name as an actual JavaScript import.

🏏

Cricket analogy: import type { Scorecard } is like a scout's notebook entry that only exists on paper, never printed onto the physical team sheet handed to the umpire; mixing it up with a real player import can cause the bundle to reference a name that was never actually on the field.

A file with no import or export statements is treated by TypeScript as a legacy "script" whose top-level declarations are global, not a module. Adding even a single export {} at the bottom of a file is a common trick to force it into module scope without exporting anything meaningful.

Gotcha: importing an interface or type alias using a plain import { Point } from "./mathUtils" (instead of import type) works today under default settings, but if isolatedModules is enabled (common in Babel/esbuild/SWC pipelines) or verbatimModuleSyntax is set, type-only symbols imported without import type can cause build failures or leave a dangling runtime import for a symbol that does not exist in the compiled JavaScript. Always use import type for types when you know a symbol is type-only.

4. Example

typescript
// logger.ts
export interface Logger {
  log(message: string): void;
}

export function createConsoleLogger(): Logger {
  return {
    log: (message: string) => console.log(`[LOG] ${message}`),
  };
}

// index.ts
import type { Logger } from "./logger";
import { createConsoleLogger } from "./logger";

const logger: Logger = createConsoleLogger();
logger.log("Application started");

5. Output

text
When compiled with `"module": "ESNext"` and run, index.ts prints:

[LOG] Application started

At compile time, `import type { Logger }` is completely erased from the emitted JavaScript for index.js  only the `createConsoleLogger` import remains as a real runtime import, because `Logger` is a type and has no runtime representation.

6. Key Takeaways

  • A TypeScript file becomes a module the moment it has a top-level import or export; otherwise it is treated as a global script.
  • Named exports use { } on import and can coexist with a single default export per file.
  • import type / export type are erased at compile time and should be used for type-only symbols, especially under isolatedModules.
  • import * as Name gathers all exports of a module into one namespace-like object.
  • TypeScript emits different runtime module formats (CommonJS, ESNext, etc.) based on the module compiler option, independent of the source syntax you write.

Practice what you learned

Was this page helpful?

Topics covered

#TypeScript#TypeScriptProgrammingStudyNotes#Programming#ModulesInTypeScript#Modules#Syntax#Explanation#Example#StudyNotes#SkillVeris