第 15 章:模块与命名空间
学习目标
- 理解 ES Module 与 TS 模块的关系
- 学会 import / export 的多种写法
- 掌握 namespace 的使用场景
- 理解声明合并与模块解析
一、ES Module 基础
typescript
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14;
export default class Calculator {
// ...
}typescript
// app.ts
import Calculator, { add, PI } from './math';
console.log(add(1, 2));
console.log(PI);
new Calculator();二、import 多种写法
typescript
// 1. 默认导入
import Calculator from './math';
// 2. 命名导入
import { add, PI } from './math';
// 3. 重命名
import { add as sum, PI as PIValue } from './math';
// 4. 全部导入为命名空间
import * as math from './math';
math.add(1, 2);
// 5. 仅类型导入(编译后擦除,体积更小)
import type { User } from './types';
// 6. 混合
import Calculator, { type User, add } from './math';⚠️ 坑 1:
import type是 TS 5.0 的优化,可以和值混合导入,避免意外把类型当作值用。Vite 项目一定要用verbatimModuleSyntax: true才能正确擦除类型导入。
三、export 多种写法
typescript
// 1. 命名导出
export const PI = 3.14;
export function add() {}
// 2. 批量
const A = 1;
const B = 2;
export { A, B };
// 3. 默认导出(每个模块只能有一个)
export default class Foo {}
// 4. 重命名导出
export { add as sum };
// 5. re-export(转发)
export { add, PI } from './math';
export * from './math'; // ⚠️ 危险:全部转发,污染命名空间⚠️ 坑 2:
export *不转发default,需要单独export { default } from ...。
四、模块解析策略
tsconfig.json:
json
{
"compilerOptions": {
"moduleResolution": "node" | "bundler" | "node16" | "nodenext"
}
}推荐:
- Vite/webpack →
"bundler" - Node.js 项目 →
"node16"或"nodenext"
五、命名空间(namespace)
typescript
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
export class LettersOnlyValidator implements StringValidator {
isValid(s: string): boolean {
return /^[A-Za-z]+$/.test(s);
}
}
}
const validator: Validation.StringValidator = new Validation.LettersOnlyValidator();
validator.isValid('Hello'); // true嵌套:
typescript
namespace A {
export namespace B {
export const x = 1;
}
}
console.log(A.B.x); // 1⚠️ 坑 3:namespace 是老的组织代码方式,现代项目优先用 ES Module,namespace 主要用于类型声明文件和全局类型扩展。
六、namespace vs ES Module
| 维度 | namespace | ES Module |
|---|---|---|
| 标准 | TS 私有 | ECMAScript |
| 文件 | 通常多文件合并 | 单文件 |
| 浏览器 | 不能直接用 | 配合打包器可 |
| 适用场景 | 全局声明、类型扩展 | 现代代码组织 |
七、全局类型声明
typescript
// global.d.ts
declare global {
interface Window {
myApp: { version: string };
}
const VERSION: string;
}
export {};⚠️ 坑 4:全局声明文件必须有
export {}才被当作模块,否则declare global不生效。
八、动态导入
typescript
async function loadMath(): Promise<void> {
const math = await import('./math');
console.log(math.add(1, 2));
}
loadMath();九、本章小结
| 要点 | 关键 |
|---|---|
| import 类型 | import type 编译期擦除,推荐 |
| export 类型 | 命名 / 默认 / 重命名 / re-export |
| 模块解析 | bundler / node16 / nodenext |
| namespace | 老的代码组织,优先用 ES Module |
| declare global | 全局声明,必须有 export {} |
| 动态导入 | await import('./module') |
动手练习
- 多文件:建
user.ts(导出接口)、app.ts(导入使用) - 类型导入:用
import type单独导入User类型,看编译后产物大小 - namespace 实战:用 namespace 组织多个 validator 类
下一章:第 16 章:声明文件 →