Closed
Description
Describe the bug
Getting
main.ts:1:23 - error TS1471: Module 'csv-parse' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
when trying to import in a project with moduleResolution: node16
.
To Reproduce
package.json
{
"dependencies": {
"csv-parse": "5.3.0",
"typescript": "4.7.4"
}
}
tsconfig.json
{
"compilerOptions": {
"moduleResolution": "Node16"
}
}
main.ts
import { parse } from 'csv-parse';
and then run:
tsc
Output I get:
$ tsc
main.ts:1:23 - error TS1471: Module 'csv-parse' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
1 import { parse } from 'csv-parse';
~~~~~~~~~~~
Found 1 error in main.ts:1
Additional context
My intent in this example is to import csv-parse using require, but typescript seems to think this library only exposes esm modules.
Typescripts esm support is not without controversies. One of them is that they are more strict about the location of .d.ts
files: microsoft/TypeScript#49160 . The most straightforward solution seems to be just duplicating the type definitions beside all entry points, but there might be better ways I am not aware of.
Activity
wdavidw commentedon Aug 2, 2022
In demo/ts-module-node16/tsconfig.json, we used
module
instead ofmoduleResolution
:Otherwise, please look at the demo and try to find what's different.
sorgloomer commentedon Aug 2, 2022
Unfortunately having
moduleResolution: node16
ornodenext
is a hard constraint for us, as this is the only setting of typescript that enables us to use dynamicimport()
statements that wouldn't get transpiled intorequire()
s. Dynamic imports would be our vehicle to deal with other esm-only modules.The difference with the new moduleResolutions settings is, to my understanding, typescript now only considers the
"exports"
entry of the package.json, and does not consider the "types" entry anymore. In microsoft/TypeScript#49160 they claim these typing issues to be due to misconfigured third party packages.I tried all the typescript configuration combinations, unfortunately none of them is covering all the usecases.
wdavidw commentedon Aug 3, 2022
Having a hard time understanding the exact need. I am not a TS user myself, just trying to help. Could you create a demo similar to ts-module-node16. Fork the repository, duplicate the
./demo/ts-module-node16
folder, modify it to suit your need and push the changes in your fork. This would help a lot.Note, my initial understand was wrong. I have tried to use dynamic import with
module
with success.sorgloomer commentedon Aug 3, 2022
Sure, thanks for considering my case! I am off for a couple of weeks, after that I'll create the fork and will attempt to alter the configuration to match my needs without breaking any of the demos. Do you mind if I keep the ticket open until then?
wdavidw commentedon Aug 3, 2022
No worry, I am myself on holidays as well. In order to not break any demo, just
cp -rp ./demo/ts-module-node16 ./demo/ts-moduleresolution-node16
.mantljosh commentedon Oct 12, 2022
I'm pretty sure the issue here is the
type: "module"
in package.json which makes TS think that everything in the package is going to be ESM (even though there is CJS as specified in theexports
)wdavidw commentedon Oct 12, 2022
Hum, that is an interesting possibility.
acidoxee commentedon Oct 29, 2022
I'm having a similar problem as well when using those CSV packages in a CJS context. I'm still not sure that's the whole story, but if I got this right, the issue is that
.cjs
files inpackages/*/dist/cjs
MUST have a sibling.d.cts
declaration file. Usingexports.*.types
fields inpackage.json
and pointing them to.d.ts
definitions does absolutely nothing, since only.d.cts
extensions would work because of the.cjs
extension of CJS files.To reproduce the problem, just do this: https://github.com/acidoxee/node-csv/commit/4e6cf591715a8dc8823989e435b5c079d6ad56a8, and look at the error on the import here: https://github.com/acidoxee/node-csv/blob/4e6cf591715a8dc8823989e435b5c079d6ad56a8/demo/ts-module-node16/lib/stringify.ts#L3.
I don't think there's any use to forcing those
exports.*.types
anyway (like it was recently added in this commit), since the declarations already seem to always be adjacent to their sibling JS files.The only appropriate fix here seems to yield matching
.d.ts
,.d.cts
and/or.d.mts
declaration files next to each JS file with a.js
,.cjs
and/or.mjs
extension respectfully.See this comment and its whole thread which seems to confirm this behavior.
wdavidw commentedon Nov 8, 2022
Does having both the "module" and "moduleResolution" set to "Node16" could resolve the issue ?
wdavidw commentedon Nov 8, 2022
Otherwise, could someone reproduce the issue in a branch inside a dedicated "./demo/{package}". Reproducing the issue would help finding a solution
LinusU commentedon Nov 9, 2022
With #368 merged, the following settings work for us:
tsconfig.json
package.json
my-file.ts
wdavidw commentedon Nov 9, 2022
OK, then let's close it.
acidoxee commentedon Dec 23, 2022
That's great for ESM! Although when consuming
csv-parse
andcsv-stringify
from a CJS module, the problem I've described previously is still present AFAICT.When writing
import { parse } from 'csv-parse'
from a CJS module with"module": "Node16"
in its corresponding TS config, theexports
map resolves to"require": "./dist/cjs/index.cjs"
for the runtime, but to"types": "./lib/index.d.ts"
for the types, which do not have the proper.d.cts
extension that's expected for TS to understand it's importing a CJS file (see my previous comment and the TS 4.7 announcement). I believe the reason is that the"type": "module"
field incsv-parse
'spackage.json
makes TS infer an ESM context everywhere, except if specifically told otherwise through a.d.cts
extension on the declaration file.Wouldn't there be a way for you to generate those declaration files in
dist/cjs
with a.d.cts
extension instead of.d.ts
? From my understanding, if you did that, you could (and even should) also entirely remove theexports.*.types
field in the export map, since declarations are already adjacent to the JS files, and all imports would work great, whether they're done from ESM or CJS.12 remaining items