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

谈谈 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
  • 模块路径统一使用相对路径,避免运行时错误。

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

相关文章:

  • 高斯数据库和ORCLE、mysql数据库的区别
  • 安装并使用conda(宏观版)
  • 【模拟】从 0 到 1:模拟算法的深度剖析与实战指南
  • /*给你一个字符串s,由若干单词组成,单词前后用一些空格隔开 单词是指由字母组成,不包含任何空字符的最大子字符串*/
  • keepalived的工作原理和脑裂
  • JWT令牌封装类/ 接口的各个请求
  • 黑马跟学.苍穹外卖.Day08
  • 【资料分享】全志科技T113-i全国产(1.2GHz双核A7 RISC-V)工业核心板规格书
  • tf1.x和tf2.x在使用上的区别和联系是什么
  • AI 原生 IDE Trae 深度体验:SSHremote 功能助力远程开发与云原生部署
  • 基于web的牙医预约管理系统(源码+lw+部署文档+讲解),源码可白嫖!
  • k8s资源管理介绍
  • 【C++指南】内存管理完全手册:new/delete
  • 修改windows npt时钟服务器
  • 工业 CPE(Customer Premises Equipment,客户终端设备)
  • 深度学习定义与分类【详细易懂 初学者友好~】
  • pgvector 向量数据库的安装方式全集
  • 【FPGA】状态机模板-分别对比一段式状态机、二段式状态机以及三段式状态机
  • 操作系统知识点32
  • MySQL事务详解:从理论到实践,保障数据一致性
  • 脱欧后首次英欧峰会召开前夕,双方却因渔业和青年流动议题僵住了
  • 玛丽亚·凯莉虹口连唱两夜,舞台绽放唤醒三代人青春记忆
  • “GoFun出行”订单时隔7年扣费后续:平台将退费,双方已和解
  • 奥古斯都时代的历史学家李维
  • 创同期历史新高!1至4月全国铁路发送旅客14.6亿人次
  • 光明日报:家长孩子共同“息屏”,也要保证高质量陪伴