Modules and Namespaces
40 minTypeScript's module system is based on ES6 modules, providing a modern way to organize and share code across files. Modules use `import` and `export` statements to define what code is accessible from other files and what code is imported from elsewhere. This module system enables better code organization, dependency management, and tree-shaking for optimized bundle sizes.
The `export` keyword makes code available to other modules. You can export variables, functions, classes, interfaces, types, and more. TypeScript supports named exports (multiple exports per file) and default exports (single export per file). Named exports are generally preferred as they provide better IntelliSense support and make it clear what's being imported.
The `import` keyword brings code from other modules into your current file. You can import named exports using destructuring syntax, import default exports directly, or import everything as a namespace. TypeScript also supports type-only imports using `import type`, which ensures types are stripped from the compiled JavaScript output, improving bundle size.
Namespaces are TypeScript's way of organizing code into logical groups and avoiding naming conflicts. They're particularly useful for organizing related code that doesn't need to be in separate files. However, in modern TypeScript development, modules are generally preferred over namespaces because they're more aligned with ES6 standards and work better with modern build tools.
Module resolution is the process TypeScript uses to find the files that correspond to import statements. TypeScript supports different module resolution strategies: `node` (Node.js-style resolution), `classic` (TypeScript's original resolution), and `bundler` (for modern bundlers). Understanding module resolution is important for configuring path aliases, resolving dependencies, and working with different module systems.
Best practices for modules include using explicit file extensions in imports (when using certain module systems), organizing related code into modules, using barrel exports (index files) for cleaner imports, and avoiding circular dependencies. Proper module organization makes code more maintainable, testable, and easier to understand.
Key Concepts
- Modules use import/export statements to share code between files.
- Named exports allow multiple exports per file; default exports allow one.
- Type-only imports (import type) don't appear in compiled JavaScript.
- Namespaces organize code but modules are generally preferred.
- Module resolution determines how TypeScript finds imported files.
Learning Objectives
Master
- Using import and export statements for module organization
- Understanding named exports vs default exports
- Using type-only imports for better bundle optimization
- Configuring module resolution and path aliases
Develop
- Code organization and modular design thinking
- Understanding module systems and dependency management
- Creating maintainable project structures
Tips
- Prefer named exports over default exports for better IntelliSense.
- Use import type for type-only imports to improve bundle size.
- Organize related code into modules for better maintainability.
- Use barrel exports (index files) to simplify imports from directories.
Common Pitfalls
- Creating circular dependencies between modules.
- Using namespaces when modules would be more appropriate.
- Not using type-only imports, leading to larger bundle sizes.
- Mixing different module systems in the same project.
Summary
- Modules use import/export to organize and share code.
- Named exports are generally preferred over default exports.
- Type-only imports improve bundle size by removing types from output.
- Modules are preferred over namespaces in modern TypeScript.
- Proper module organization improves code maintainability.
Exercise
Create a module with exported functions and import them.
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
// main.ts
import { add, multiply } from './math';
console.log(add(5, 3)); // 8
console.log(multiply(4, 2)); // 8
Exercise Tips
- Use default exports: export default class Calculator { ... }
- Re-export modules: export { add, multiply } from './math';
- Use namespace imports: import * as MathUtils from './math';
- Create type-only imports: import type { User } from './types';