网站搜索

javascript - Node.js ESM 下的 TypeScript 分歧


Node.js ESM 的工作方式似乎与 TypeScript 不同。

这导致了程序能够通过类型检查,但在运行时却会崩溃。

package.json

{
  "dependencies": {
    "@types/lodash": "^4.0.0",
    "lodash": "^4.0.0",
    "typescript": "^4.0.0"
  },
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "module": "es2015"
  }
}

a.ts

import { partition } from "lodash";

partition([1, 2, 3, 4], n => n % 2);

跑

npm install
node_modules/.bin/tsc -p .
node index.js

然后程序崩溃了:

file:///home/paul/test44/index.js:1
import { partition } from "lodash";
         ^^^^^^^^^
SyntaxError: Named export 'partition' not found. The requested module 'lodash' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'lodash';
const { partition } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:179:5)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)
    at async handleMainPromise (node:internal/modules/run_main:63:12)

我如何才能使 TypeScript 和 Node.js 的 ESM 保持一致,以便类型检查与运行时行为匹配?


编辑:

我尝试过在 "module": "nodenext" 下使用 typescript@next。

同样的错误发生了。

答案#1

问题是你在混用 ES 和 CommonJS 模块;错误信息的文本里有写。这仍然是一个相对较新的概念,当你期望模块……应该……可以正常工作时,很容易忽略。

TypeScript 只提供 import 语句,然后它们会被转译为你选择的模块系统;在 ESM 的情况下,由于语法上相似,所以转译的内容并不多。

既然你正在转译为 ESM,问题不在于 TypeScript;问题在于底层的 Node.js 引擎以及它如何处理混合模块系统。你已经用 ESM(当然,是使用 TypeScript)写了一些东西,并且你正试图导入其他用 CommonJS 编写的内容。

为了执行依赖 CommonJS 模块的代码,你需要:

  1. 使用你依赖项的 ESM 版本(并非所有依赖项都提供!)
  2. 使用 module.createRequire() 以可用的形式导入 CommonJS 模块

来源:

https://nodejs.org/api/esm.html#no-require-exports-or-moduleexports https://nodejs.org/api/module.html#modulecreaterequirefilename