特性 | 模块(Modules) | 命名空间(Namespaces) |
---|---|---|
设计目的 | 实现代码的物理隔离与依赖管理(文件级作用域) | 解决全局命名冲突,逻辑分组代码(非文件依赖) |
依赖管理 | 显式导入导出(import/export ),依赖关系清晰 |
隐式合并(/// 或全局声明) |
编译结果 | 生成独立模块文件(如 CommonJS/ESM) | 生成全局对象(IIFE 模式),易污染全局作用域 |
适用场景 | 现代前端/Node.js 项目、大型应用、跨团队协作 | 旧项目迁移、小型脚本、全局类型声明(.d.ts ) |
Tree-Shaking | ✅ 支持(优化打包体积) | ❌ 不支持(所有成员被保留) |
关键结论:新项目优先使用模块,命名空间仅用于兼容旧代码或特定场景。
// 模块化示例:清晰依赖管理
// math.ts
export const add = (a: number, b: number) => a + b;
// app.ts
import { add } from './math'; // 显式导入
console.log(add(2, 3)); // 5
npm
发布独立功能包,避免全局污染.d.ts
) // 全局扩展示例
declare namespace Express {
interface Request {
user: { id: string };
}
}
避免模块内嵌套命名空间
// 反模式:冗余封装
export namespace Utils { // 不必要!
export function log() {}
}
// 正解:直接导出函数
export function log() {}
模块本身已是封装单位,嵌套命名空间会增加冗余访问路径(如
Utils.Utils.log()
)。
禁止混合使用模块与三斜杠指令
/// // 错误!
import { modernFunc } from './module'; // 冲突
模块依赖应统一用
import
。
迁移策略:从命名空间转向模块
namespace X { export ... }
改为直接 export
///
为 import
tsconfig.json
启用 "module": "ESNext"
tsconfig.json
){
"compilerOptions": {
"module": "ESNext", // 现代模块标准
"moduleResolution": "Node", // 支持 node_modules 解析
"baseUrl": "./src",
"paths": { // 路径别名提升可读性
"@utils/*": ["utils/*"],
"@components/*": ["app/components/*"]
},
"esModuleInterop": true // 改善 CJS/ESM 互操作
}
}
若需保留旧命名空间,通过 declare global
合并到全局类型:
// legacy.d.ts
declare global {
namespace LegacyLib {
interface Config { ... }
}
}
graph TD
A[新项目?] -->|是| B[使用模块]
A -->|否| C{旧代码含全局变量?}
C -->|是| D[命名空间过渡+逐步迁移]
C -->|否| E[直接使用模块]
B --> F[配置模块路径别名]
D --> F
E --> F
核心准则:
- ✅ 模块化是未来:拥抱 ES 标准,适配构建工具链(Webpack/Vite)
- ⚠️ 命名空间为特例:仅用于兼容或类型扩展,避免在新逻辑中使用
完整迁移案例可参考 TypeScript 官方模块指南。