Modules and imports
Programs are directory trees of .ts files. The compiler starts at the entry file you give it and compiles everything it imports into one binary. Module resolution is tsc's (moduleResolution: bundler), so specifiers are written the way TypeScript already accepts them: ./util, ./util.js, ./util.ts, ./dir/index.
ts
// Named, default and namespace imports; a re-export; type-only imports.
import { area, type Shape } from "./geometry.js";
import describe from "./describe";
import * as units from "./units";
const shapes: Shape[] = [
{ kind: "circle", size: 1 },
{ kind: "square", size: 3 },
];
for (const s of shapes) {
console.log(describe(s), units.format(area(s), units.SQUARE_METERS));
}ts
export interface Shape {
kind: "circle" | "square";
size: number;
}
export function area(s: Shape): number {
return s.kind === "circle" ? Math.PI * s.size * s.size : s.size * s.size;
}ts
import type { Shape } from "./geometry";
export default function describe(s: Shape): string {
return `${s.kind}(${s.size})`;
}ts
export { SQUARE_METERS } from "./constants";
export function format(value: number, unit: string): string {
return `${Math.round(value * 1000) / 1000} ${unit}`;
}ts
export const SQUARE_METERS = "m2";text
circle(1) 3.142 m2
square(3) 9 m2What is supported
- Named imports and exports,
export { x as y }, default exports and imports. - Namespace imports (
import * as u from "./u"). They compile to static references, so the namespace must be used asu.name, not passed around as a value. - Re-exports:
export * from "./m"andexport { x } from "./m". - Type-only imports and exports (
import type,import { type T }). - Built-in modules:
node:fs,node:fs/promisesandnode:path, in named, default and namespace forms. See node:fs and node:path. - Packages in
node_moduleswhose entry resolves to TypeScript source. They are compiled whole-program like your own files.
Every top-level symbol is namespaced by its module, and each module's top-level code runs once, in dependency order, as in Node.
What is rejected
| Form | Code | Instead |
|---|---|---|
require, module.exports, export = | CS1226 | ESM import / export |
dynamic import() | CS1226 | a static import |
a package that ships only .js + .d.ts | CS1226 | run that program on Node |
| using a namespace import as a value | CS1226 | refer to ns.member directly |
| reading a module variable before its declaration runs | CS1228 | move the declaration up |
node:process as an importable module is not supported yet; use the global process.
Next: Classes and interfaces.