polkadot-js / api

Promise and RxJS APIs around Polkadot and Substrate based chains via RPC calls. It is dynamically generated based on what the Substrate runtime provides in terms of metadata.
Apache License 2.0
1.07k stars 354 forks source link

Import broken for CJS-targeted TypeScript projects #5711

Closed rflechtner closed 2 weeks ago

rflechtner commented 1 year ago

EDIT: updated the reproduction example to reflect the proper use of typescript's Node16 module setting.

The following setup currently results in a TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. error thrown by TypeScript:

index.ts

import * as api from '@polkadot/api'

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",             
    "module": "NodeNext", // using Node16 or setting "moduleResolution": "Node16" results in the same behaviour
  }
}        

package.json "type" is set to "commonjs" or omitted, both of which result in code being emitted for the commonjs module system (alternatively, the error can be provoked by renaming index.ts to index.cts, which has the same effect)

The reason for that is likely that typings are only provided in the root of the project, which, due to the top-level type field is interpreted as ESM, as when using Node16/NodeNext module settings TS follows node's logic for inferring module type. The type export strategy may need to be adjusted to allow properly importing from a TS project that builds to CJS.

I'm still struggling myself to figure out how to use the conditional exports map correctly to make TS aware of both a CJS and ESM implementation being present in a package, but from first experiments with strategies mentioned in this issue I can report that the following strategies seem to fix this:

  1. Move .d.ts files to cjs folder instead Because the CJS folder contains a package.json with "type": "commonjs", the typings are now interpreted as CJS. While TS takes issue with with CJS trying to import ESM, the converse is not the case. Not sure we'd provoke other unexpected issues with that though, so better:

  2. Provide separate typings for CJS code Build CJS code with declarations, living in the CJS folder. You'd obviously have to modify the exports map as well, the following strategies seem to work:

    • 2a) Remove "types" entry from exports map entirely. As long as there is a *.d.ts file accompanying every *.js export Typescript seems to be picking them automatically.
    • 2b) Point to the right declaration file for each import strategy, e.g.
      ".": {
      "import": {
      "types": "./index.d.ts",
      "default": "./index.js"
      },
      "require": {
      "types": "./cjs/index.d.ts",
      "default":  "./cjs/index.js"
      }
      },
TarikGul commented 2 weeks ago

This is now fixed in 14.1.1

polkadot-js-bot commented 1 week ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.