当前位置: 首页 > article >正文

谈谈 TypeScript 中的模块系统,如何使用 ES Modules 和 CommonJS 模块?

模块系统是 TypeScript 项目组织代码的核心机制,主要用于代码拆分、复用和依赖管理。

TypeScript 支持 ​ES Modules(ESM)​ 和 ​CommonJS 两种主流模块系统,理解它们的差异和使用场景是前端开发中的必备技能。

以下从基础语法、配置、互操作性到实战建议展开说明。


一、ES Modules(ESM):标准化的模块系统

1. 基础语法
ESM 使用 import/export 语法,是 ECMAScript 官方标准,适用于现代浏览器和 Node.js(需配置)。

// math.ts
// 具名导出
export const add = (a: number, b: number): number => a + b;
// 默认导出
export default function subtract(a: number, b: number): number {
  return a - b;
}

// app.ts
import { add } from './math.js';  // 导入具名导出(注意编译后路径)
import subtract from './math.js'; // 导入默认导出

console.log(add(1, 2));      // 3
console.log(subtract(5, 3)); // 2

关键点

  • 导入路径需明确文件扩展名(如 .js),因编译后代码为 JS。
  • 默认导出和具名导出需区分使用(影响导入语法)。

二、CommonJS:Node.js 的传统模块系统

1. 基础语法
CommonJS 使用 require/module.exports,常见于 Node.js 环境。

// math.ts
// 具名导出
exports.add = (a: number, b: number): number => a + b;
// 默认导出(需特殊处理)
export default function subtract(a: number, b: number): number {
  return a - b;
}

// app.ts
const math = require('./math'); // 导入整个模块
const { add } = require('./math'); // 解构具名导出
const subtract = require('./math').default; // 导入默认导出(需配置支持)

console.log(add(1, 2));      // 3
console.log(subtract(5, 3)); // 2

关键点

  • 默认导出需通过 module.exports 或 exports.default 处理。
  • 直接使用 require 可能导致类型丢失,需配合 TypeScript 类型声明。

三、配置 TypeScript 模块解析

1. tsconfig.json 核心配置项

  • module: 指定编译后的模块系统(如 "ES6" 或 "CommonJS")。
  • esModuleInterop: 允许 ESM 和 CommonJS 的互操作性(建议开启)。
  • allowSyntheticDefaultImports: 兼容无默认导出的模块。
{
  "compilerOptions": {
    "module": "ES6",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

四、模块互操作性:混用 ESM 和 CommonJS

1. 在 ESM 中导入 CommonJS 模块
需开启 esModuleInterop,TypeScript 会自动处理兼容。

// 导入 CommonJS 模块(如 lodash)
import _ from 'lodash'; // 默认导入(esModuleInterop 生效)
import * as lodash from 'lodash'; // 命名空间导入(无 esModuleInterop 时)

2. 在 CommonJS 中导入 ESM 模块
需使用动态 import() 或编译为 CommonJS 格式。

// 动态导入(Node.js 环境)
const math = await import('./math.js');
console.log(math.add(1, 2));

五、实战建议与避坑指南

1. 统一模块系统

  • 新项目优先使用 ​ESM,尤其是前端项目或 Node.js 新版本。
  • 旧项目沿用 ​CommonJS,避免混用导致编译后代码混乱。

2. 第三方库兼容性

  • 检查库的模块格式:
    • ESM 库通常包含 "type": "module"
    • CommonJS 库可能需 @types/xxx 补充类型。

3. 默认导出陷阱

  • CommonJS 默认导出需显式声明:
// 错误:默认导出未正确处理
module.exports = { add, subtract };
// 正确:需通过 default 或 esModuleInterop
export default { add, subtract };

4. 路径与扩展名

  • ESM 严格依赖完整路径(如 './math.js'),CommonJS 可省略扩展名。
  • TypeScript 编译时自动处理路径,但需确保运行时路径正确。

5. 循环依赖

  • 避免模块 A 导入 B,同时 B 导入 A,可能导致未定义行为。
  • 重构代码或使用延迟加载(如函数内导入)。

六、总结

TypeScript 的模块系统选择需结合项目环境:

  • 前端项目/现代 Node.js:ESM 是未来趋势,配合 esModuleInterop 实现平滑迁移。
  • 传统 Node.js 项目:CommonJS 更稳定,注意默认导出的兼容性处理。

核心配置建议

  • 开启 esModuleInterop 和 allowSyntheticDefaultImports
  • 模块路径统一使用相对路径,避免运行时错误。

通过合理配置和规范使用,可高效管理代码依赖,避免常见的模块陷阱。


http://www.kler.cn/a/591329.html

相关文章:

  • STM32---FreeRTOS内存管理实验
  • 剑指 Offer II 109. 开密码锁
  • 【go】soilid与设计模式
  • 【Leetcode】203.移除链表元素
  • MyBatis 如何创建 SqlSession 对象的?
  • 手抖护理指南:全方位守护患者生活
  • 华为ISC+战略规划项目数字化转型驱动的智慧供应链革新(169页PPT)(文末有下载方式)
  • 为什么Django能有效防御CSRF攻击?
  • 爬虫基础之爬取猫眼Top100 可视化
  • Qt之自定义界面组件 一
  • 地宫取宝---dfs‘记忆
  • Python核心:Django鉴权方案全解析
  • Android第四次面试总结(基础算法篇)
  • SpringCloud 学习笔记2(Nacos)
  • 实验9-2 高级搜索技术2
  • browser-use WebUI + DeepSeek 基于AI的UI自动化解决方案
  • 苹果宣布iOS 19将支持RCS 3.0,短信功能迎来大升级
  • 微信小程序:修改提示信息placeholder颜色
  • 【亲测有效,已顺利上线】你好,你的小程序涉及提供播放、观看等服务,请补充选择:文娱-其他视频类目。(多种没有资质的解决方案)
  • 自动驾驶背后的数学:特征提取中的线性变换与非线性激活