esModuleInterop 在 tsconfig 中:TypeScript 完全指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么 esModuleInterop 不仅仅是 tsconfig 中的一个勾选项

\n\n

如果你曾经使用 TypeScript 编写过代码,并导入过像 express 或 lodash 这样的库,那么你很可能遇到过编译器对 import * as express from 'express' 报错的情况。或者,你虽然可以正常使用 import express from 'express',但在生成的 JavaScript 代码中却看到了一个奇怪的构造 module.exports.default。这是什么魔法?其实,这个魔法(或者说它的缺失)就是 tsconfig.json 中的 esModuleInterop 标志。

\n\n

这个参数是 Stack Overflow 上最热门的问题之一(有数千次浏览!),这并不奇怪:如果不理解它,很容易陷入模块不兼容的陷阱。在本教程中,我们不仅会解释理论,还会通过实际示例,带你从问题走向解决方案。我们开始吧!

\n\n

问题:两个模块世界的冲突

\n\n

TypeScript 是 JavaScript 的超集,而 JavaScript 历史上主要有两种模块系统:

\n
    \n
  • CommonJS (CJS) — Node.js 的标准,使用 require() 和 module.exports。示例:const express = require('express');
  • \n
  • ES 模块 (ESM) — 现代标准,使用 import 和 export。示例:import express from 'express';
  • \n
\n

问题在于,这两种系统处理默认导出(default export)的方式不同。在 ESM 中,一个模块可以有一个 export default,并通过 import name from 'module' 导入。在 CommonJS 中,没有“默认导出”的概念——只有 module.exports 对象,它可以是任何东西。

\n\n

当 TypeScript 将你的代码编译为 CommonJS(这在 Node.js 中经常需要)时,它必须决定:如何将 import x from 'y' 表示为 require()?如果没有 esModuleInterop,TypeScript 会按字面意思处理:创建一个 module.exports.default,这会破坏针对 CommonJS 编写的库的导入。

\n\n

什么是 esModuleInterop?

\n\n

esModuleInterop 是 tsconfig.json 中的一个标志,用于启用 CommonJS 和 ES 模块之间的额外兼容性。当它设置为 true 时,TypeScript 会生成辅助代码,允许你为没有 default 导出的 CommonJS 模块编写 import foo from 'bar'。

\n\n

在 TypeScript 4.x 及更高版本中,此标志默认为 true(如果你使用 --init),但在旧项目中,它经常被关闭。为什么?因为它会改变导入的行为,如果不理解,就会导致错误。

\n\n

在 tsconfig.json 中如何配置

\n
{\n  "compilerOptions": {\n    "esModuleInterop": true,\n    // 其他设置...\n  }\n}\n
\n\n

启用此标志还会自动启用 allowSyntheticDefaultImports,它允许从没有实际 default 导出的模块进行默认导入(在类型层面)。

\n\n

分步教程:从问题到解决方案

\n\n

让我们通过一个实际例子来分析这种情况。假设我们有一个基于 CommonJS 的简单库:

\n\n
// myLib.js (CommonJS)\nmodule.exports = function greet(name) {\n  return `Hello, ${name}!`;\n};\n
\n\n

我们想在 TypeScript 项目中使用它。创建一个 index.ts 文件:

\n\n
// index.ts\nimport greet from './myLib';\nconsole.log(greet('World'));\n
\n\n

现在,让我们看看在 esModuleInterop 的不同设置下编译时会发生什么。

\n\n

步骤 1:没有 esModuleInterop (false)

\n\n

使用 "esModuleInterop": false 运行编译。TypeScript 会报错:

\n
Module '"myLib"' has no d                

博客

书籍推荐