C.W.K.
Stream
Lesson 01 of 05 · published

ES Modules: import, export, default

~9 min · modules, esm, imports

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"One file per module. Import what you need; export what others need."

The ESM model

In ES Modules, each file is its own module with its own scope. Variables declared at the top level are private to the file unless you export them. To use them in another file, you import. There's no global namespace; everything is scoped.

This is the standard JavaScript module system. TypeScript adopts it directly — no special syntax, no transpilation hacks (when targeting modern environments). The same import/export you write in TypeScript runs natively in modern Node.js, Bun, Deno, and browsers.

Named exports vs default exports

Named: export function greet() { ... }; import with import { greet } from './mod'. The name is fixed at the export site; you can alias on import with as.

Default: export default class Foo { ... }; import with import Foo from './mod'. The importer chooses the name. One default per module.

Modern style guides lean toward named exports — they keep names consistent across imports, support better tree-shaking with bundlers, and make refactoring with rename-symbol IDE actions reliable. Default exports remain in some libraries (React itself, for example) for historical reasons.

Re-exports

export { greet } from './mod' re-exports from another module without importing locally. Common in index.ts barrel files that consolidate a directory's public API.

Default to named exports. They scale better in larger codebases. Reach for default exports only when a module truly has a single primary export (a React component file, for example).

Code

Named exports, default exports, re-exports·typescript
// math.ts — multiple named exports.
export function add(a: number, b: number): number { return a + b }
export function sub(a: number, b: number): number { return a - b }
export const PI = 3.14159;

// main.ts
import { add, sub, PI } from './math';
import * as math from './math';            // namespace import
import { add as plus } from './math';      // alias

add(1, 2);            // 3
math.PI;              // 3.14159
plus(1, 2);           // 3 — same function, different name

// component.ts — default export.
export default function Button() { /* ... */ }

// app.ts
import Button from './component';           // name your import
import AnyName from './component';           // works too — default exports are name-flexible

// Re-export from a barrel.
// index.ts
export { add, sub, PI } from './math';
export { default as Button } from './component';

External links

Exercise

Create a folder with three files: add.ts, sub.ts, and index.ts. The first two export functions; index re-exports both. Import from index in a fourth file. Confirm the types flow correctly through the re-export.
Hint
The barrel pattern (index.ts that re-exports everything from a directory) is how libraries expose their public API. Consumers import from one place; the directory structure stays free to change behind the curtain.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.