Organise large codebases with ES modules, declaration files, and module augmentation.
What you will see
saved: Ada
About 2 min of reading
Quick check
Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.
Try It
Modules export values and types; other modules import them by name. `export` makes members public, `import` pulls them back, and only runtime exports are bundled. Multi-file import/export snippets are DISPLAY-ONLY, but the equivalent single-file version runs in Node.
1
ES module exports
function add(a, b) { return a + b; }
const Point = null;
console.log(add(2, 3));
const p = { x: 1, y: 2 };
console.log(p.x + p.y);
Before you run it, say out loud what it will print. Then open the answer.
What it prints
5
3
2
Default vs named exports
function greet() { return "hi"; }
const version = "1.0";
console.log(greet(), version);
Before you run it, say out loud what it will print. Then open the answer.
What it prints
hi 1.0
3
Type-only imports
function db_save(u) { return "saved: " + u.name; }
const u = { name: "Ada" };
console.log(db_save(u));
Before you run it, say out loud what it will print. Then open the answer.
What it prints
saved: Ada
Put it in order
Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.
Data Flow
A module exports declarations; other modules import them by name; the compiler resolves types while the runtime bundles only real values.
1Module exports values and types
↓
2Consumer imports with named or default syntax
↓
3Compiler resolves types from the module
↓
4Bundler includes only runtime exports
Why this worksModule resolution
TypeScript must find the types for an import. Configuration matters:
NodeNext follows Node's real resolution rules, including package.jsonexports maps and requiring file extensions for ESM. Getting resolution right avoids Could not find a declaration file for module errors.
.d.ts files contain types only, no runtime code. Libraries ship them so TypeScript users get full intellisense and checking against plain JS.
Examples
ES module exports
Public API
// math.tsexportconst add = (a: number, b: number): number => a + b;
exporttype Point = { x: number; y: number };
// main.tsimport { add, Point } from"./math";
const p: Point = { x: 1, y: 2 };
export makes declarations public; import brings them back. Only exported members are visible to other modules, everything else stays private.
Default vs named exports
Two export styles
export default functiongreet() { return"hi"; } // defaultexportconst version = "1.0"; // named
A module has at most one default export but many named exports. Named imports use braces { version }; default imports do not. Mixing them is common for a primary export plus helpers.
Type-only imports
Avoid runtime cost for types
importtype { User } from"./types";
import { db } from"./db";
functionsave(u: User) { db.save(u); }
import type is erased at compile time, so a type import never adds a runtime dependency. With verbatimModuleSyntax or isolatedModules, it is required to avoid shipping unused imports.
Words this lesson uses
Each one is defined here on this site. Open the entry for the full definition and the other words it points at.