Skip to content

fix: fix CommonJS type resolution#608

Merged
merencia merged 1 commit into
node-cron:mainfrom
wojtekmaj:fix-cjs-type-resolution
Jul 4, 2026
Merged

fix: fix CommonJS type resolution#608
merencia merged 1 commit into
node-cron:mainfrom
wojtekmaj:fix-cjs-type-resolution

Conversation

@wojtekmaj

@wojtekmaj wojtekmaj commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

The package currently points both ESM and CJS consumers at the same declaration file:

"exports": {
  ".": {
    "types": "./dist/node-cron.d.ts",
    "import": "./dist/node-cron.js",
    "require": "./dist/node-cron.cjs"
  }
}

That breaks typed CommonJS consumers using Node16/NodeNext-style resolution. For example, this is a normal way to consume a CommonJS package from a .cts file:

import cron = require("node-cron");

cron.schedule("* * * * *", () => {});

With the current package metadata, TypeScript rejects it with:

error TS1471: Module 'node-cron' cannot be imported using this construct.
The specifier only resolves to an ES module, which cannot be imported with 'require'.
Use an ECMAScript import instead.

Static imports in a CommonJS TypeScript file fail too:

import cron from "node-cron";
error 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'.
Consider writing a dynamic 'import("node-cron")' call instead.

The package does have a CommonJS runtime entry (dist/node-cron.cjs), so consumers should not need to switch to dynamic import() just to satisfy TypeScript. The problem is that TypeScript sees the shared dist/node-cron.d.ts file as ESM because this package has "type": "module".

This PR gives the import and require branches their own type declarations:

"exports": {
  ".": {
    "import": {
      "types": "./dist/node-cron.d.ts",
      "default": "./dist/node-cron.js"
    },
    "require": {
      "types": "./dist/node-cron.d.cts",
      "default": "./dist/node-cron.cjs"
    }
  }
}

Rollup now emits dist/node-cron.d.cts alongside dist/node-cron.d.ts. After that, the import cron = require("node-cron") example type-checks correctly.

Previously, arethetypeswrong returned:

node10            ok
node16 (from CJS) Masquerading as ESM
node16 (from ESM) ok (ESM)
bundler           ok

Now it returns:

No problems found

node10            ok
node16 (from CJS) ok (CJS)
node16 (from ESM) ok (ESM)
bundler           ok

Checked with:

npm run build
npm run typecheck
npm test
npm pack --dry-run --json
npx @arethetypeswrong/cli --pack . --format table --no-color

@wojtekmaj wojtekmaj changed the title Fix CommonJS type resolution fix: Fix CommonJS type resolution Jul 3, 2026
@wojtekmaj wojtekmaj changed the title fix: Fix CommonJS type resolution fix: fix CommonJS type resolution Jul 3, 2026
@merencia

merencia commented Jul 4, 2026

Copy link
Copy Markdown
Member

Hey @wojtekmaj thank you!

Merging this into main. I still have a few tests to run on main before releasing 4.6, which I'm planning to finish this weekend.

@merencia
merencia merged commit ee9d294 into node-cron:main Jul 4, 2026
9 of 11 checks passed
@wojtekmaj
wojtekmaj deleted the fix-cjs-type-resolution branch July 4, 2026 05:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants