
在 TypeScript 中,"esModuleInterop": true是一个模块互操作性配置 ,核心作用是解决 ES 模块(ESM)与 CommonJS 模块之间的兼容问题,让两种模块系统的导入/导出语法能更自然地协同工作。
一、先理解背景:ESM 与 CommonJS 的核心差异
TypeScript 支持两种主流模块规范:
-
ES 模块(ESM) :使用
import/export语法(如import foo from 'foo'、export default bar),是现代 JS 的标准模块系统。 -
CommonJS :Node.js 传统的模块系统,使用
require()/module.exports(如const foo = require('foo')、module.exports = bar)。
两者的默认导出逻辑完全不同:
-
ESM 的
export default是明确的"默认导出",对应import foo from 'foo'。 -
CommonJS 没有"默认导出"的概念,
module.exports本质是一个对象 (所有导出都挂在这个对象上)。如果强行用import foo from 'foo'导入 CommonJS 模块,TS 会默认认为你要取module.exports.default------但大多数 CommonJS 模块并没有设置exports.default,导致导入结果不符合预期(比如得到undefined)。
二、esModuleInterop: true的具体作用
开启该配置后,TypeScript 会自动处理两种模块系统的"翻译"工作,主要带来以下便利:
1. 允许用 ESM 的默认导入语法(import foo from 'foo')导入 CommonJS 模块
这是最常见的痛点。例如,你想导入 Node.js 内置的 fs模块(CommonJS):
-
未开
esModuleInterop:必须用命名空间导入或整体导入:import * as fs from 'fs'→ 使用时需fs.readFileSync();若强行写
import fs from 'fs',TS 会认为你要取fs.default(但实际fs模块没有这个属性),导致fs为undefined。 -
开了
esModuleInterop:可以直接用默认导入:import fs from 'fs'→ TS 会自动将fs映射到module.exports(即 CommonJS 的导出对象),等价于const fs = require('fs')。
2. 自动生成辅助函数,处理复杂的模块转换
为了兼容两种模块系统,TS 会在编译后的 JS 代码中插入辅助函数 (如 __importDefault、__importStar),负责将 CommonJS 模块"包装"成 ESM 风格的对象:
-
__importDefault(mod):将 CommonJS 模块的module.exports作为"默认导出"(对应import foo from 'foo')。 -
__importStar(mod):将 CommonJS 模块的module.exports作为"命名空间导出"(对应import * as foo from 'foo')。
这些辅助函数是 TS 内置的,无需手动维护,确保编译后的代码能在 Node.js 或浏览器中正确运行。
3. 隐含开启 allowSyntheticDefaultImports
esModuleInterop: true会自动启用 另一个配置 allowSyntheticDefaultImports: true(允许用默认导入语法导入没有显式默认导出的模块)。因此不需要再单独设置后者。
三、举个例子:直观感受差异
假设你有一个 CommonJS 模块 utils.js:
// utils.js(CommonJS)
module.exports = {
add: (a, b) => a + b,
sub: (a, b) => a - b
};
-
未开
esModuleInterop:导入时必须用命名空间或整体导入:import * as utils from './utils'; // 正确,utils 是 { add, sub } 的对象 import utils from './utils'; // 错误!TS 认为要取 utils.default(不存在) -
开了
esModuleInterop:可以用默认导入,更符合直觉:import utils from './utils'; // 正确!TS 自动将 module.exports 作为默认导出 console.log(utils.add(1, 2)); // 3(正常工作)
四、适用场景
-
导入 CommonJS 第三方库 :比如 Node.js 内置模块(
fs、path)、旧版 npm 包(很多库仍用 CommonJS)。 -
混合使用 ESM 和 CommonJS :项目中同时有
.ts(ESM)和.js(CommonJS)文件时,避免导入报错。 -
更自然的代码风格 :希望统一用 ESM 的
import语法,而不是混写import和require。
五、注意事项
-
编译后的代码体积:辅助函数会增加极小的代码量(可忽略),不影响性能。
-
与
module配置的配合 :通常搭配module: "CommonJS"(Node.js 环境)或module: "ESNext"(现代浏览器/打包工具)使用,效果最佳。 -
不要与
noEmitHelpers冲突 :如果手动关闭了辅助函数生成(noEmitHelpers: true),需要自己引入@babel/helpers或类似库,否则会报错。
总结
esModuleInterop: true是 TypeScript 中提升模块互操作性的关键配置,它让你可以:
-
用 ESM 的
import foo from 'bar'自然导入 CommonJS 模块; -
避免手动处理
module.exports与export default的转换; -
写出更简洁、符合现代 JS 风格的代码。

惠州西湖