Modules in TypeScript
Introduction
TypeScript uses the same module syntax as modern JavaScript: import and export. The compiler checks types across files, emits JavaScript modules according to tsconfig, and can interoperate with CommonJS in Node. This chapter covers organizing .ts files, export styles, and how TypeScript treats modules differently from plain JS.
Prerequisites
- Your First TypeScript Program
- JavaScript ES Modules (helpful background)
moduleandmoduleResolutionset intsconfig.json(see install chapter)
One File, One Module
Each .ts file with top-level import or export is its own module. Files without them are global scripts (avoid in apps—use modules).
src/
math.ts
app.tssrc/math.ts:
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14159;src/app.ts:
import { add, PI } from "./math.js";
const total = add(2, 3);
console.log(total, PI);Code explanation:
./math.jsextension in import is common withmoduleResolution: "NodeNext"—TypeScript resolves tomath.tsat compile time- Types of
addandPIflow intoapp.tsautomatically
Tip
Extension in Imports
With Node16/NodeNext, use .js in import paths for emitted ESM even though source is .ts. Bundlers may allow extensionless paths—follow your toolchain docs.
Named and Default Exports
Named (multiple per file):
export interface User {
id: number;
name: string;
}
export function formatUser(user: User): string {
return `${user.name} (#${user.id})`;
}Default (one primary export):
export default class Logger {
log(message: string): void {
console.log(message);
}
}Import styles:
import Logger from "./logger.js";
import { User, formatUser } from "./user.js";Re-exports
Barrel file pattern:
// src/models/index.ts
export { User, formatUser } from "./user.js";
export type { User as UserModel } from "./user.js";Code explanation:
export typere-exports only types (erased at runtime withverbatimModuleSyntax/importsNotUsedAsValuessettings)- Barrels simplify imports but can hurt tree-shaking if overused
import type and export type
Type-only imports never emit runtime requires:
import type { User } from "./user.js";
function demo(user: User): void {
console.log(user.name);
}export type { User };
export { formatUser };Keeps bundles clean when verbatimModuleSyntax is enabled.
CommonJS Interop (Node)
Legacy Node code uses require / module.exports. TypeScript can emit or consume CommonJS depending on module in tsconfig.
ESM import from a CJS package (typical modern setup):
import pkg from "some-cjs-package";With esModuleInterop: true, default import often works for module.exports = ....
Writing CJS-style in .ts (when configured):
import fs = require("node:fs");
export = {
read(): string {
return fs.readFileSync("/tmp/demo.txt", "utf8");
},
};export = targets CommonJS module.exports. Prefer ESM for new projects.
Dynamic import
async function loadLocale(code: string): Promise<{ greet: (name: string) => string }> {
const module = await import(`./locales/${code}.js`);
return module.default;
}Returns a Promise of the module namespace; types can be asserted or declared.
Resolution Hints
TypeScript resolves imports using moduleResolution (next chapter). Errors like “Cannot find module” usually mean:
- Wrong path or missing
.jssuffix for NodeNext - Package not installed
- Missing types for JS package (
@types/...)
Practical Layout
src/
index.ts # entry
lib/
math.ts
models/
user.ts
index.ts # optional barrelsrc/index.ts:
import { add } from "./lib/math.js";
import { formatUser } from "./models/user.js";
console.log(add(1, 2));
console.log(formatUser({ id: 1, name: "Ada" }));FAQ
.ts import vs .js import?
Source is .ts; emitted file is .js. NodeNext ESM expects import specifiers that match runtime files.
Can I use require in TypeScript?
Possible with certain module settings; ESM is the default for new Node and frontend projects.
Are types exported at runtime?
No. Interfaces and type aliases disappear. Values (class, function, const) remain.
Circular imports?
TypeScript allows them but they cause runtime issues if values are used before initialization. Refactor shared types to a third file.
import.meta?
Supported in ESM for import.meta.url etc., with appropriate module target.
Same as JavaScript modules?
Syntax matches JS. TypeScript adds type checking and import type / export type.