Incompatible with TypeScript when moduleResolution === nodenext
SirPepe opened this issue · comments
TypeScript refuses to use the type definitions for uhtml when moduleResolution
is set to nodenext
in tsconfig.json
.
package.json:
{
"name": "uhtml-bug-ts-nodenext",
"version": "0.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"typescript": "^5.2.2",
"uhtml": "^3.2.1"
}
}
tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "nodenext",
"strict": true
},
"include": [
"**/*"
]
}
src/test.ts:
import { html, render } from "uhtml";
// Could not find a declaration file for module 'uhtml'. '/home/peter/uhtml-bug-ts-nodenext/node_modules/uhtml/esm/index.js' implicitly has an 'any' type.
// There are types at '/home/peter/uhtml-bug-ts-nodenext/node_modules/uhtml/index.d.ts', but this result could not be resolved when respecting package.json "exports". The 'uhtml' library may need to update its package.json or typings.ts(7016)
As far as I understand it, the exports
entries in package.json
need their own type
fields next to import
and default
to fix this: https://www.typescriptlang.org/docs/handbook/esm-node.html#packagejson-exports-imports-and-self-referencing
I think this module is not TS at all and there is not even JSDoc TS in it so that I cannot really add types, this is a JS project.
Is TS really incapable of using JS projects these days? That's a really bad move for the ecosystem, if that's the case.
@SirPepe from Xwitter I got this answer:
https://twitter.com/shvr93/status/1699341735246143819?s=20
For or JS only modules ambient declarations should “fix” everything:
declare module "uhtml";
As far as I understand it, this is what is going on: uhtml has types
in package.json
, but this field nowadays has the same relevance as main
, browser
and the like. What really matters is what's in exports
, and today's TypeScript expects there to be a types
field for everything in exports
if some configuration options for TS (like moduleResolution: nodenext
) are set.
So the proper way to get rid of this problem is to add "types": "./index.d.ts",
to everything in exports
:
{
"name": "uhtml",
"version": "3.2.1",
"description": "A micro HTML/SVG render",
"main": "cjs/index.js",
"types": "index.d.ts", // keep this
"module": "./esm/index.js",
"type": "module",
// more...
"exports": {
".": {
"types": "./index.d.ts", // add this
"import": "./esm/index.js",
"default": "./cjs/index.js"
},
"./async": {
"types": "./index.d.ts", // add this
"import": "./esm/async.js",
"default": "./cjs/async.js"
},
"./init": {
"types": "./index.d.ts", // add this
"import": "./esm/init.js",
"default": "./cjs/init.js"
},
"./json": {
"types": "./index.d.ts", // add this
"import": "./esm/json.js",
"default": "./cjs/json.js"
},
"./jsx": {
"types": "./index.d.ts", // add this
"import": "./esm/x.js",
"default": "./cjs/x.js"
},
"./package.json": "./package.json"
},
// more...
}
Basically, keep the top-level types
field for backwards compatibility but also add an extra types
for each export. In my mind it makes sense to have it set up like this because it is not entirely inconceivable to have different types for different exports. Making it your job to deal with the breaking changes that an entirely unrelated project introduces is the dick move of the century, but apart from that minor fact, it kinda makes sense.
I'd be OK with that PR, thanks!
it's up and running 🥳