简体   繁体   中英

TypeScript with Node.js ESM disagreement

Node.js ESM seems work differently than TypeScript.

It's resulting in programs that pass typechecking and yet crash at runtime.

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);

Run

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

And the program crashes:

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)

How can I bring TypeScript and Node.js ESM into alignment, so that typechecking matches runtime behavior?


EDIT:

I have tried using typescript@next with "module": "nodenext" .

The same error happens.

The problem is that you're mixing ES and ComonJS modules; it's in the text of the error message. This is still a relatively new concept and is easy to miss when you'd expect that modules... should... just work.

TypeScript only provides import statements, which they will then transpile to your chosen module system; in the case of ESM, there's not a whole lot to transpile as they're syntactically similar.

Since you're transpiling to ESM, the problem is not TypeScript; it's the underlying Node.js engine and how it deals with mixed module systems. You've written something in ESM (granted, using TypeScript) and you're trying to import something else written in CommonJS.

In order to execute your code depending on a CommonJS module, you either need to:

  1. Use the ESM version of your dependency (and not all dependencies provide one!)
  2. Use module.createRequire() to import the CommonJS module in a usable form

Sources:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM