A TypeScript module is a file that exports or imports something. Modules keep code organized by giving each file a clear responsibility and by making dependencies explicit.
Without modules, large projects quickly become difficult to navigate. With modules, utilities, models, services, components, and API clients can live in separate files while still working together through imports and exports.
TypeScript modules use JavaScript module syntax. TypeScript adds type checking, type-only imports, and compiler settings that control how modules are resolved and emitted.
Add one worked example that compares the normal path with the boundary case for TypeScript Modules: import, export and Type-Only Imports.
TypeScript Modules import export and Type-Only Imports should be studied as a practical TypeScript lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
export const TAX_RATE = 0.18;
Named exports are explicit and easy to search. A file can export many named values, and importers choose exactly what they need.
Named exports are usually a strong default for utilities, constants, shared models, service functions, and feature helpers because refactors are clearer and accidental name changes are easier to catch.
import { add, TAX_RATE } from "./math";
export function calculateInvoice(subtotal: number): number {
const tax = subtotal * TAX_RATE;
return add(subtotal, tax);
}
A default export represents the main value from a file. Default exports are common for page components, one primary class, or a module that naturally exposes one main thing.
Use default exports intentionally. In larger shared utility files, named exports are often easier to maintain because every imported name is tied to the exported name.
| Export Style | Common Use |
|---|---|
| Named export | Utilities, constants, models, multiple public values. |
| Default export | One main component, class, or service from a file. |
| Mixed exports | Use carefully so the file API stays obvious. |
export default class UserService {
findName(id: number): string {
return id === 1 ? "Admin" : "Guest";
}
}
// app.ts
import UserService from "./UserService";
const service = new UserService();
console.log(service.findName(1));
import type imports only type information. The import is erased from compiled JavaScript because interfaces and type aliases do not exist at runtime.
Using import type makes intent clear and can avoid build problems in projects that enforce isolated modules or strict module syntax. It also helps developers see which dependencies are runtime dependencies and which are only for checking.
import { calculateInvoice } from "./billing";
import type { User } from "./types";
const user: User = {
id: 1,
name: "Admin",
};
console.log(user.name, calculateInvoice(1000));
A feature folder may contain several files. An index.ts file can re-export the public pieces so other parts of the app import from one stable path.
Use this carefully. Re-exporting everything from everywhere can create confusing dependency graphs. Export only the API that other folders should depend on.
export type { User, UserRole } from "./user.types";
export { createUserService } from "./user.service";
export { validateUserInput } from "./user.validation";
Path aliases make imports shorter and more stable. Instead of importing from ../../../services/users, a project might use @/services/users.
Aliases are usually configured in tsconfig.json and must also be understood by the bundler or runtime. TypeScript can type-check an alias, but the tool that runs the code must know how to resolve it too.
import { createUserService } from "@/features/users";
import type { User } from "@/features/users";
export async function loadProfile(id: number): Promise<User | null> {
const service = createUserService();
return service.findById(id);
}
Good modules have clear ownership. A feature module should expose what other parts of the app need and keep internal helpers private. This prevents unrelated code from depending on implementation details.
If a shared folder becomes a dumping ground, it becomes hard to understand. Prefer specific shared modules such as date, money, http, or validation over vague folders like misc.
| Module Choice | Effect |
|---|---|
| Small focused file | Easy to test and reuse. |
| Feature index file | Clean public imports for a folder. |
| Deep private import | Can create fragile dependencies. |
| Circular import | Can cause confusing runtime behavior. |
Most module problems come from unclear ownership. A shared folder should not become a dumping ground, and feature modules should avoid reaching deeply into each other’s private files.
Keep imports pointed at public entry points when possible. If a file is imported from many unrelated places, it may belong in a shared utility package or it may need a clearer abstraction.
TypeScript Modules import export and Type-Only Imports matters in TypeScript because it changes how a program is written, tested, or debugged. The page should explain the normal flow first: what the developer writes, what the runtime or platform does, and what result should appear.
When teaching TypeScript Modules import export and Type-Only Imports, avoid stopping at syntax. Show the surrounding decision: why this feature is chosen, what problem it removes, and what would become harder if the feature were not used.
1. Define the input for TypeScript Modules import export and Type-Only Imports.
2. Apply the rule from the lesson.
3. Compare the actual result with the expected result.
4. Record the fix if the result differs.
1. Try empty, missing, duplicate, or invalid data.
2. Identify where TypeScript Modules import export and Type-Only Imports changes behavior.
3. Explain the safest correction.
4. Retest the normal path.
Memorizing TypeScript Modules import export and Type-Only Imports without the situation where it is useful.
Connect TypeScript Modules import export and Type-Only Imports to a concrete TypeScript task.
Testing TypeScript Modules import export and Type-Only Imports only with the perfect input.
Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Changing code before reading the visible symptom or error message.
Inspect the output, state, configuration, or stack trace connected to TypeScript Modules import export and Type-Only Imports.
Memorizing TypeScript Modules import export and Type-Only Imports without the situation where it is useful.
Connect TypeScript Modules import export and Type-Only Imports to a concrete TypeScript task.
The common mistake is memorizing syntax without understanding when the behavior changes or fails.
Remember the problem it solves in TypeScript, then attach the syntax or steps to that problem.
You can predict the result of a small example, explain a failure case, and choose it over a nearby alternative for a clear reason.
They often copy the syntax but skip the state, input, dependency, selector, route, type, or configuration that controls the behavior.
Explore 500+ free tutorials across 20+ languages and frameworks.