JSX type regression in 4.13.10: `IntrinsicElements` recursively references itself
What version of Hono are you using?
4.13.10 (The reproduction passes with 4.13.9)
What runtime/platform is your app running on? (with version if possible)
Node.js 26.10.0, TypeScript 7.0.2
What steps can reproduce the bug?
Create these three files:
package.json
{
"private": true,
"type": "module",
"devDependencies": {
"hono": "4.13.10",
"typescript": "7.0.2"
}
}tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",
"lib": ["DOM", "ES2024"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"types": []
},
"include": ["index.tsx"]
}index.tsx
export const valid = <button disabled={false}>Hello</button>
// @ts-expect-error disabled must be a boolean
export const invalid = <button disabled="yes">Hello</button>Then, run
npm install
npx tscThe same failure can be seen using "jsxImportSource": "hono/jsx/dom".
What is the expected behavior?
Compilation should succeed. The valid element should pass the type-check; the invalid disabled attribute should produce an error covered by the @ts-expect-error.
What do you see instead?
node_modules/hono/dist/types/jsx/base.d.ts(20,13):
error TS2310: Type 'IntrinsicElements' recursively references itself as a base type.
index.tsx(3,1):
error TS2578: Unused '@ts-expect-error' directive.The IntrinsicElements declaration is broken. As a result, features like standard attributes are no longer type-checked.
Additional information
Background
I caught this in CI for an automated hono upgrade today: https://github.com/jeremybanka/lasertag/pull/373
Diagnosis
The published 4.13.10 declaration in dist/types/jsx/base.d.ts imports IntrinsicElements without an alias, then uses the same name inside the JSX namespace:
import { IntrinsicElements, JSX as JSX$1 } from "./intrinsic-elements.js";
// ^ Not actually used!
export declare namespace JSX {
// ...
interface IntrinsicElements extends IntrinsicElements {
[tagName: string]: Props;
}
}In 4.13.9, the imported interface was aliased as IntrinsicElementsDefined, and the namespace interface extended that alias.
Restoring that alias resolves this reproduction for both JSX runtimes.
Source: honojs/hono