Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type definition generated for CommonJS output using module.exports = is not usable #51

Open
2 tasks
i-like-robots opened this issue Dec 20, 2023 · 0 comments
Labels
bug Something isn't working

Comments

@i-like-robots
Copy link

i-like-robots commented Dec 20, 2023

Problem

The type definition file generated for CommonJS output using module.exports = syntax is not consumable by TS projects without esModuleInterop enabled or JS projects with type checking or editors with support for type hints on JavaScript files.

For example, given this TypeScript input:

// src/index.ts
export default function Foo() {}

The JavaScript file generated when using pkgroll v2.0.1 will be:

// dist/index.cjs
module.exports = function Foo() {}

And this will be created along with the following type definition:

// dist/index.d.cts
declare function Foo(): void;

export { Foo as default };

However, when a project using CommonJS modules consumes the compiled files like so:

// @ts-check
const Foo = require('./dist/index.cjs');

new Foo()

Then they will receive the following error when running a type check on their code or attempting to use type hints in their editor because these are expecting the implementor to reference a property named "default":

This expression is not constructable.
  Type 'typeof import("/Users/matthinchliffe/Code/test-case/dist/index")' has no construct signatures.ts(2351)

Because there's no equivalent of module.exports = with ESM the Rollup documentation suggests always using named export mode to avoid creating two different interfaces:

In other words for those tools, you cannot create a package interface where const lib = require("your-lib") yields the same as import lib from "your-lib". With named export mode however, const {lib} = require("your-lib") will be equivalent to import {lib} from "your-lib".

So whilst neither of these may be ideal I understand there are two potential solutions for this problem:

  1. Manipulate the type definition to output export = syntax.
  2. Use Rollup's named export mode to output exports.default =

(p.s. apart from this hiccup, the project has been A+, thank you)

Expected behavior

The module imported using require should have the correct type definition applied and editor type hints enabled. The following type definition would work:

declare function Foo(): void;

export = Foo;

Alternatively, the following generated JS would work:

exports.default = function Foo() {}

Minimal reproduction URL

https://gist.github.com/i-like-robots/29b8662210f6898626f40d49e8e39e68

Version

v2.0.1

Node.js version

v18.18

Package manager

npm

Operating system

macOS

Contributions

  • I plan to open a pull request for this issue
  • I plan to make a financial contribution to this project
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant