1. esModuleInterop
esModuleInterop
是 TypeScript 编译器(tsc
)的核心配置项之一,作用是解决 ES 模块(ESM)与 CommonJS 模块(Node.js 传统模块格式)的兼容性问题,让 TypeScript 项目能更顺畅地混用两种模块系统的代码。
使用示例:
js
// tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}
2. 核心背景:ESM 与 CommonJS 的 "不兼容点"
ESM(用 import
/export
)和 CommonJS(用 require
/module.exports
)是两种不同的模块规范,直接混用会有两个关键冲突:
- 默认导出的差异 :
CommonJS 模块没有 "默认导出" 概念(如module.exports = { foo: 1 }
是整体导出一个对象),但 ESM 允许import defaultExport from '模块'
的默认导入语法。若不处理,直接用 ESM 语法导入 CommonJS 模块(如import fs from 'fs'
)会报错。 - 命名导出的缺失 :
CommonJS 模块无法直接提供 ESM 风格的 "命名导出"(如export const foo = 1
),若强行用import { readFile } from 'fs'
导入 CommonJS 模块的属性,TypeScript 会无法识别类型。
3. esModuleInterop
的作用:自动 "桥接" 两种模块
开启 esModuleInterop: true
后,TypeScript 会在编译时自动做两件事,消除兼容性问题:
-
生成 "默认导入适配代码" :
对 CommonJS 模块,自动添加一层适配逻辑,让 ESM 的默认导入(
import xxx from '模块'
)能正确识别 CommonJS 的module.exports
导出。例如编译
import fs from 'fs'
时,会自动处理为类似const fs = require('fs').default || require('fs')
的逻辑,确保能拿到 CommonJS 模块的整体导出。 -
提供
__importDefault
和__importStar
辅助函数 :编译后的代码会注入这两个辅助函数,分别处理 "默认导入" 和 "整体导入(
import * as xxx from '模块'
)",确保两种导入方式都能正确适配 CommonJS 模块。
4. 推荐搭配:allowSyntheticDefaultImports
通常会和 allowSyntheticDefaultImports: true
一起配置(TypeScript 3.7+ 后,开启 esModuleInterop
会自动启用此选项):
allowSyntheticDefaultImports
仅作用于类型检查阶段,允许 TypeScript 识别 "对 CommonJS 模块的默认导入" 为合法语法(不报错);esModuleInterop
则作用于编译输出阶段,生成实际能运行的适配代码。
总结
- 核心价值:让 TypeScript 项目可以自由混用 ESM 语法和 CommonJS 模块(如 Node.js 内置模块、npm 中大量的 CommonJS 包),无需手动写适配代码。
- 使用建议 :在 Node.js 或需要兼容 CommonJS 模块的 TypeScript 项目中,必须开启 (
tsconfig.json
中设置"esModuleInterop": true
),否则会频繁遇到模块导入的语法 / 类型错误。