superstruct
superstruct copied to clipboard
Fix compatibility with Node16/NodeNext moduleResolution
When setting ModuleResolution to NodeNext
in a project's tsconfig.json
and using ESM within that project, superstruct's types fail to be discovered. I am fairly sure this is due to the fact that index.d.ts
imports other type declarations without file extensions.
It would be a fairly simple fix to change imports to use .js
file extensions, which do work, even for type declarations, and shouldn't break anything.
Duplicates #1160
Would be nice to get a resolution to this / #1160 - just ran into this today 🤞
Same here, cannot integrate Superstruct in Superforms v2 due to this.
Opened a PR for this issue in #1211
I am testing version 1.0.5-0 which, as I understand it, is a pre-release for the fix to this issue.
It works OK if I put "moduleResolution":"node16"
in my tsconfig.json
.
However it seems to fail for me when I also use "module": "node16"
along with it.
This is what is recommended for node 20 by https://www.npmjs.com/package/@tsconfig/node20 so I would expect superstruct to work with this common configuration. But maybe I am misunderstanding something.
My index.ts
file is like this:
import { object, string } from 'superstruct';
const User = object({ foo: string() });
and I get this error:
index.ts:1:32 - 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("superstruct")' call instead.
To convert this file to an ECMAScript module, change its file extension to '.mts', or add the field `"type": "module"` to '/home/ugo/superstructure-test/package.json'.
1 import { object, string } from 'superstruct';
Am I missing something or should this work too ?
@nerochiaro The TS error actually explains it correctly — you are importing an ECMAScript module (superstruct
in this case) from a CommonJS module. That's currently not allowed by Node.js.
The underlying cause is a bit obscured by TypeScript in this case, but it's the equivalent of doing something like this:
// File: index.cjs <- a CommonJS module because of .cjs
const { hello } = require("./hello.mjs")
hello()
// File: hello.mjs <- a ECMAScript module because of .mjs
export function hello() {
console.log("hello world")
}
Trying to run this with Node you get the following error:
Error [ERR_REQUIRE_ESM]: require() of ES Module <path>/hello.mjs not supported.
Instead change the require of <path>/hello.mjs to a dynamic import() which is available in all CommonJS modules.
In TypeScript codebases, I find it best to set the package.json type
field to "module", which solves this issue.
{
"type": "module",
// ...plus all the other usual fields
}
This has been resolved in 2.0!