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

Add the types condition to the package.json#exports #60

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Andarist
Copy link

@Andarist Andarist commented Feb 3, 2023

This is required for TypeScript to work with packages that have exports when using the new moduleResolution: node16/nodenext/bundler settings. When those are not used then TypeScript just ignores package.json#exports - but when you make it aware of exports by using those options then it requires the types to be included in exports and not as the top-level key of package.json

Copy link

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an improvement, but may still cause problems. The correct solution is to add an index.d.mts file. See “Types are CJS, but implementation is ESM” at https://github.com/arethetypeswrong/arethetypeswrong.github.io.

@Andarist
Copy link
Author

Andarist commented Feb 3, 2023

I find it harder to reason when the types condition is not there because it's implicit/hidden from the reader. exports promote explicitness and I think it's good to extend that to types as well. Of course, YMMV and you might have your own opinions etc. I wonder though - would this be correct here?

{
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.mts"
        "default": "./dist/index.mjs"
      },
      "require": {
        "types": "./dist/index.d.ts"
        "default": "./dist/index.js"
      }
    }
}

I guess that this would be correct but it would come with a super small perf penalty as the runtime would have to resolve one more level of nesting.

@andrewbranch
Copy link

Yes, that would work. The perf penalty is negligible.

@Andarist
Copy link
Author

Andarist commented Feb 6, 2023

Both files could have the very same content, right? They can't "proxy" to the same file though, IIUC. So this solution would require me to copy the .d.ts file and save it with a different extension.

@andrewbranch
Copy link

Yes, or have the ESM types re-export from the CJS types.

@Andarist
Copy link
Author

Andarist commented Feb 6, 2023

I pushed out what I believe is correct now. Would you mind taking another look at this @andrewbranch ?

However, this particular module might still have problems.

The generated .d.ts contains import { Plugin } from 'vite';. And on that line we get:

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("vite")' call instead.ts(1479)

Note that Plugin is only used as a type here but I can't make it work with both import type and import { type Plugin }.

A separate thing is that Vite is a module - that cannot be required but they provide a require condition. However, I'm not sure how one would re-export their module-based .d.ts as .d.cts

@andrewbranch
Copy link

You should be able to use an import type—import("vite").Plugin. This still resolves with the resolution-mode of the file (CJS in this case), but on the checking end, is allowed to resolve to an ES module. Note also that I’m planning to investigate whether type-only imports can be allowed to resolve to ES module from CJS modules: microsoft/TypeScript#52529.

@Andarist
Copy link
Author

Andarist commented Feb 6, 2023

You should be able to use an import type—import("vite").Plugin.

In this instance, it's quite problematic because this whole thing is generated by tsup. So I don't have a lot of control over this (I think?).

Note also that I’m planning to investigate whether type-only imports can be allowed to resolve to ES module from CJS modules: microsoft/TypeScript#52529.

This would be sweet

tsukkiren added a commit to tsukkiren/automerge-patcher that referenced this pull request Apr 23, 2023
When using the new `"moduleResolution": "bundler"` option in TypeScript 5 I came across an error with the type definitions:

```
Could not find a declaration file for module '@onsetsoftware/automerge-patcher'. '/Users/ben/dev/crdt-test/node_modules/@onsetsoftware/automerge-patcher/dist/automerge-patcher.es.js' implicitly has an 'any' type.
  There are types at '/Users/ben/dev/crdt-test/node_modules/@onsetsoftware/automerge-patcher/dist/types/index.d.ts', but this result could not be resolved when respecting package.json "exports". The '@onsetsoftware/automerge-patcher' library may need to update its package.json or typings.ts(7016)
```

To fix this I've updated package.json to correctly link the declaration files (as seen in a similar pull request here: gxmari007/vite-plugin-eslint#60 )
tsukkiren added a commit to tsukkiren/automerge-patcher that referenced this pull request Apr 23, 2023
When using the new `"moduleResolution": "bundler"` option in TypeScript 5 I came across an error with the type definitions:

```
Could not find a declaration file for module '@onsetsoftware/automerge-patcher'. '/Users/ren/dev/crdt-test/node_modules/@onsetsoftware/automerge-patcher/dist/automerge-patcher.es.js' implicitly has an 'any' type.
  There are types at '/Users/ren/dev/crdt-test/node_modules/@onsetsoftware/automerge-patcher/dist/types/index.d.ts', but this result could not be resolved when respecting package.json "exports". The '@onsetsoftware/automerge-patcher' library may need to update its package.json or typings.ts(7016)
```

To fix this I've updated package.json to correctly link the declaration files (as seen in a similar pull request here: gxmari007/vite-plugin-eslint#60 )
@init-center
Copy link

@gxmari007 can you merge this PR to fix the error:
There are types at '/Users/xxx/Desktop/my-project/node_modules/vite-plugin-eslint/dist/index.d.ts', but this result could not be resolved when respecting package.json "exports". The 'vite-plugin-eslint' library may need to update its package.json or typings.

tennox added a commit to tennox/hybrids that referenced this pull request Jun 11, 2023
Needed for newer typescript with certain moduleResolution settings.

Found the explanation & solution here:
gxmari007/vite-plugin-eslint#60

& the docs for the option here:
https://nodejs.org/api/packages.html#packages_exports
(with `types` being defined here: https://nodejs.org/api/packages.html#conditional-exports)
tennox added a commit to tennox/web3.storage that referenced this pull request Jun 15, 2023
Needed for newer typescript with certain moduleResolution settings.

Found the explanation & solution here:
gxmari007/vite-plugin-eslint#60

& the docs for the option here:
https://nodejs.org/api/packages.html#packages_exports (with `types` being defined here: https://nodejs.org/api/packages.html#conditional-exports)
@rtmann
Copy link

rtmann commented Aug 26, 2023

Not the ideal end solution, but you can also just turn off typescript's enforcement of this in your tsconfig.json

        "resolvePackageJsonImports": false,
        "resolvePackageJsonExports": false,

Another option is you can use patch-package and just modify the package.json you want to add the exports/imports to and then apply the patch in your project.

iainmerrick added a commit to iainmerrick/MIMEText that referenced this pull request Oct 12, 2023
See TypeScript issue here: microsoft/TypeScript#52363
I don't entirely follow what TS is doing, but I've based this commit on a PR
linked from that discussion: gxmari007/vite-plugin-eslint#60

I don't think this will work for CJS imports as TS seems to be pedantic around
file suffixes -- we may need to copy or wrap the .d.ts file somehow.
I'll investigate that separately.
gobengo pushed a commit to web3-storage/web3.storage that referenced this pull request Nov 11, 2023
Needed for newer typescript with certain moduleResolution settings.

Found the explanation & solution here:
gxmari007/vite-plugin-eslint#60

& the docs for the option here:
https://nodejs.org/api/packages.html#packages_exports (with `types`
being defined here:
https://nodejs.org/api/packages.html#conditional-exports)

Co-authored-by: Manu [tennox] <tennox+git@txlab.io>
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.

4 participants