question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

NodeNext resolution failed to resolve dual-package correctly

See original GitHub issue

Bug Report

NodeNext resolution failed to resolve dual-package correctly

🔎 Search Terms

NodeNext

🕗 Version & Regression Information

  • Never worked

💻 Code

https://github.com/Jack-Works/ts-nodenext-wrong-resolution-reproduction

where node_modules/testpkg/package.json is

{
    "name": "testpkg",
    "exports": {
      ".": {
        "types": "./dist/type.d.ts",
        "require": "./dist/common.cjs",
        "import": "./dist/module.mjs"
      }
    }
  }

TypeScript should resolve type.d.ts in dual mode instead of CommonJS synthetic export.

🙁 Actual behavior

src/index.ts:2:1 - error TS2349: This expression is not callable.
  Type 'typeof import("testpkg/dist/type")' has no call signatures.

🙂 Expected behavior

No error

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:2
  • Comments:22 (12 by maintainers)

github_iconTop GitHub Comments

2reactions
olivier-martin-sfcommented, Oct 18, 2022

I am one of the maintainers of a “dual-package” and after reading this thread I have some questions related to the thread comments:

  1. Is that correct that we should have one type declaration per file?
  2. Should the type declarations uses the matching import/export semantics for the module system they are matching? (export for .d.mjs and module.exports for .d.cjs)
  3. Does TypeScript will assume that a file ending with .d.ts is going to be an ESM if the type property is set to module in the package manifest?

More detailed below:

The package in question is declared as ES Module (the type property is set to module in the package manifest file). The package doesn’t have main entry points per se and is structured as follows:

├── dist/
    ├── foo/
        ├── someFile.cjs  # Common JS
        ├── someFile.d.ts # Type declaration  
        ├── someFile.js   # ESM

In this case, both the CJS and the ESM implementation expose the exact same API (actually the CJS implementation is transpiled from the ESM one via Rollup inside a compiler).

That’s how the exports look like for each implementation:

# someFile.js (ESM)
export default class C {}
# someFile.cjs (CJS)
class C {}
module.exports = C;

That’s how the type declaration looks like:

export default class C {}

And that’s how we configured the exports map in the package manifest:

"./*": {
    "types": "./dist/*.d.ts",
    "import": "./dist/*.js",
    "require": "./dist/*.cjs"
}

As soon as TS 4.8 has been released I tried to switch moduleResolution to NodeNext but it seems like I am hitting issues due to the fact that I am only using one declaration file if my understanding is correct. So basically, the format of my export map is wrong and I should opt for something close to what @DanielRosenwasser suggested.

I am also asking as the type declaration is being generated from our compiler and I will have to think about how we can generate one for CJS if we have to.

For instance, while trying to use the package in a project that uses CommonJS I am getting the following error from tsserver:

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' (ts1479)

Thanks in advance for your input.

1reaction
olivier-martin-sfcommented, Oct 24, 2022

That makes sense, thanks a lot for all the very useful information, I can see what I should be doing now!

Read more comments on GitHub >

github_iconTop Results From Across the Web

@rollup/plugin-node-resolve - npm
According to NodeJS module resolution require statements should resolve using the require condition in the package exports field, while es ...
Read more >
Typescript module resolution not working - Stack Overflow
When I hover the 'utils/IntHelper' part in my import line in the typescript file VSCode would also show the correct path to that...
Read more >
ES Modules in NodeJS - Troubleshooting Resources
I'm going to just say it - the transition to ESM (ES Modules) in NodeJS has not been easy or pain-free for most...
Read more >
8.2 Release Notes Red Hat Enterprise Linux 8
RHEL 8.2 includes the setools-gui and setools-console-analyses packages that ... A dual-layer DVD or USB key is recommended when using the Binary DVD...
Read more >
rollup | Yarn - Package Manager
Bug Fixes. Correctly resolve preserveModulesRoot in Vite (#4591) ... #4416: Add Typescript 4.5 nodenext node12 module resolution support (@frank-dspeed) ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found