Modules
- #typescript
- #modules
- #import
- #export
In questa lezione
1. Introduction
Any real TypeScript project is split across multiple files. Modules are how those files share code with each other: a file exports the values, functions, classes, or types it wants to make available, and other files import them. TypeScript’s module system builds directly on top of JavaScript’s ES Modules (ESM) syntax, adding full type-checking across file boundaries.
There are two flavors of exports — named exports and a default export — and understanding the difference (and when to reach for each) is fundamental to organizing a codebase well.
2. Named exports
A named export exposes a value under a specific, fixed name. A module can have as many named exports as it wants:
// math-utils.ts
export function add(x: number, y: number): number {
return x + y;
}
export const VALUE = 42;
Anything marked export becomes importable, by that exact name, from other files.
3. Default export
A module can also have a single default export — at most one per file:
// math-utils.ts (continued)
function test() {
return "test";
}
export default test;
Suggerimento
Default export is convenient when a module has one clear “main” thing to offer (a component, a class, a single function). The importing file is free to name it however it likes, since there’s no fixed export name to match against.
Putting the whole file together:
// math-utils.ts
function test() {
return "test";
}
export function add(x: number, y: number): number {
return x + y;
}
export const VALUE = 42;
export default test;
4. Importing named exports
To import one or more named exports, use curly braces and match the exact exported name:
// main.ts
import { add, VALUE } from "./math-utils";
console.log(add(1, 10)); // 11
console.log(VALUE); // 42
Attenzione
Named imports must match the exported name exactly (you can rename locally with as, e.g. import { add as sum } from "./math-utils";, but the original export name still has to exist). Misspelling a named import is a compile error, not a silent undefined.
5. Importing the default export
The default export can be imported under any local name you choose — that’s the whole point of it being “default” rather than named:
// main.ts (continued)
import Something from "./math-utils";
console.log(Something()); // "test"
Nothing forces the imported name to be test, Something, or anything related to the original name — the module only ever exposes one default, so there’s no ambiguity about which value you’re importing.
Combining a default import with named imports in the same statement is also valid:
import Something, { add, VALUE } from "./math-utils";
6. Namespace-style imports
Instead of listing individual named exports, you can import everything a module exports as a single namespace object:
// main.ts
import * as MathUtils from "./math-utils";
console.log(MathUtils.add(2, 3)); // 5
console.log(MathUtils.VALUE); // 42
console.log(MathUtils.default()); // "test" — the default export becomes a `.default` property
This style is handy when a module exports many related utilities and you want to keep them grouped under one recognizable prefix, or when you want to avoid naming collisions between imports from different modules.
7. Re-exporting from another module
A module can also forward another module’s exports without importing them locally first — a re-export. This is common in “barrel” files that aggregate several modules into one entry point:
// index.ts
export * from "./math-utils";
export * from "./string-utils";
Consumers can now do import { add } from "./index"; without knowing that add actually lives in math-utils.ts. You can also re-export selectively:
// index.ts
export { add, VALUE } from "./math-utils";
Nota
export * from "./math-utils" re-exports every named export, but it does not forward a default export. To re-export a default as well, you need an explicit export { default } from "./math-utils"; (optionally renaming it, e.g. export { default as test } from "./math-utils";).
8. How this connects to tsconfig.json
The import/export syntax you write is the same regardless of target environment, but how TypeScript compiles it down to actual JavaScript module code depends on the module and moduleResolution options in tsconfig.json (covered in the very first lesson of this section). Modern JavaScript runtimes (browsers, current Node.js versions) understand ESM natively, while older Node.js tooling historically relied on CommonJS (require/module.exports). Setting "module": "ESNext" or "module": "NodeNext" versus "module": "CommonJS" changes the emitted output — and can also affect small but important details like whether a default import needs interop handling. When in doubt, match the module/moduleResolution settings to whatever runtime or bundler is actually going to execute the compiled code.
9. Further reading
10. Quiz
Mettiti alla prova
0/6 risposte
How many default exports can a single TypeScript module have?
What must match exactly when importing a named export?
Why can
import Something from "./math-utils";use any local name?What does
import * as MathUtils from "./math-utils";do?Does
export * from "./math-utils";forward the module's default export?What tsconfig.json option primarily controls how import/export syntax is compiled to JavaScript (ESM vs CommonJS)?
11. Exercises
Scenario: You are organizing a small utilities library with separate files for string helpers and math helpers, plus a single entry point for consumers.
Task:
- Create
string-utils.tswith two named exports:capitalize(s: string): stringandslugify(s: string): string. - Create
math-utils.tswith named exportsadd,VALUEand a default exporttest, as shown in this lesson. - Create an
index.tsthat re-exports everything from both files usingexport * from "./string-utils";andexport * from "./math-utils";. - Write a
main.tsthat importscapitalize,add, andVALUEall from./index(not from the original files directly), and confirm it type-checks and runs correctly. - Add an explicit re-export of
math-utils’s default export fromindex.ts(e.g.export { default as mathTest } from "./math-utils";) and importmathTestinmain.ts.
Learning objective: practice organizing named and default exports across multiple files and aggregating them through a barrel file with re-exports.
Scenario: You’re deciding between a namespace-style import and individual named imports for a module that exports a dozen small helper functions.
Task:
- Take the
math-utils.tsmodule from this lesson and add three more named exports of your choice (e.g.subtract,multiply,divide). - In one file, import all four arithmetic functions individually with named imports and use them.
- In a second file, import the whole module with
import * as MathUtils from "./math-utils";and call the same four functions through the namespace object. - Write a short comment comparing the two files: which reads more clearly, and which would be easier to maintain if
math-utils.tsgrew to twenty exports?
Learning objective: compare named imports against namespace imports in practice and form an opinion on when each style is preferable.