Repository navigation
Description
Acknowledgement
- I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion.
Comment
While implementing the MDX content mapper I paid a lot of attention to how TypeScript reports JSX related errors. I’ll gladly provide more context if needed, but the TL;DR is that it maps to JSX, and users can inject custom JSX components using a _components object.
I noticed that JSX related type errors are inconsistent, excessive, and sometimes even have incorrect messages. The errors all point the user into a direction to solve the error, but I believe DX can be improved.
Example
Let’s say we have the following files:
// package.json
{
"type": "module",
"dependencies": {
"@types/react": "19.3.0",
"typescript": "7.1.0-beta"
}
}// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"module": "preserve",
"noEmit": true
}
}// code.jsx
export function Component() {
const _components = {
div: 'div',
dov: 'dov'
} as const
return (
<>
<div></div>
<dov></dov>
<dav></dav>
<div></dov>
<div></dav>
<_components.div></_components.div>
<_components.dov></_components.dov>
<_components.dav></_components.dav>
<_components.div></_components.dov>
<_components.div></_components.dav>
</>
)
}In my editor, I see 15 errors.
Since this file has syntax errors, tsc only reports syntactic errors:
$ tsc
code.tsx:12:14 - error TS17002: Expected corresponding JSX closing tag for 'div'.
12 <div></dov>
~~~
code.tsx:13:14 - error TS17002: Expected corresponding JSX closing tag for 'div'.
13 <div></dav>
~~~
code.tsx:17:26 - error TS17002: Expected corresponding JSX closing tag for '_components.div'.
17 <_components.div></_components.dov>
~~~~~~~~~~~~~~~
code.tsx:18:26 - error TS17002: Expected corresponding JSX closing tag for '_components.div'.
18 <_components.div></_components.dav>
~~~~~~~~~~~~~~~
Found 4 errors in the same file, starting at: code.tsx:12- All error messages make sense
- The error messages underline the full JSX closing tag name (
_components.dov)
Let’s fix these errors:
// code.tsx
export function Component() {
const _components = {
div: 'div',
dov: 'dov'
} as const
return (
<>
<div></div>
<dov></dov>
<dav></dav>
<_components.div></_components.div>
<_components.dov></_components.dov>
<_components.dav></_components.dav>
</>
)
}$ tsc
code.tsx:10:7 - error TS2339: Property 'dov' does not exist on type 'JSX.IntrinsicElements'.
10 <dov></dov>
~~~~~
code.tsx:10:12 - error TS2339: Property 'dov' does not exist on type 'JSX.IntrinsicElements'.
10 <dov></dov>
~~~~~~
code.tsx:11:7 - error TS2339: Property 'dav' does not exist on type 'JSX.IntrinsicElements'.
11 <dav></dav>
~~~~~
code.tsx:11:12 - error TS2339: Property 'dav' does not exist on type 'JSX.IntrinsicElements'.
11 <dav></dav>
~~~~~~
code.tsx:13:7 - error TS2339: Property 'dov' does not exist on type 'JSX.IntrinsicElements'.
13 <_components.dov></_components.dov>
~~~~~~~~~~~~~~~~~
code.tsx:13:8 - error TS2604: JSX element type '_components.dov' does not have any construct or call signatures.
13 <_components.dov></_components.dov>
~~~~~~~~~~~~~~~
code.tsx:14:20 - error TS2339: Property 'dav' does not exist on type '{ readonly div: "div"; readonly dov: "dov"; }'.
14 <_components.dav></_components.dav>
~~~
code.tsx:14:38 - error TS2339: Property 'dav' does not exist on type '{ readonly div: "div"; readonly dov: "dov"; }'.
14 <_components.dav></_components.dav>
~~~
Found 8 errors in the same file, starting at: code.tsx:10Let’s break down these errors:
code.tsx:10:7 - error TS2339: Property 'dov' does not exist on type 'JSX.IntrinsicElements'. 10 <dov></dov> ~~~~~ code.tsx:11:7 - error TS2339: Property 'dav' does not exist on type 'JSX.IntrinsicElements'. 11 <dav></dav> ~~~~~
This makes sense. Note that the scope is the entire JSX open tag (<dov>)
code.tsx:10:12 - error TS2339: Property 'dov' does not exist on type 'JSX.IntrinsicElements'. 10 <dov></dov> ~~~~~~ code.tsx:11:12 - error TS2339: Property 'dav' does not exist on type 'JSX.IntrinsicElements'. 11 <dav></dav> ~~~~~~
This is redundant repetition. The same error was reported for the open tags. Note that the scope is the entire JSX closing tag (</dov>)
code.tsx:13:7 - error TS2339: Property 'dov' does not exist on type 'JSX.IntrinsicElements'. 13 <_components.dov></_components.dov> ~~~~~~~~~~~~~~~~~
This makes sense. Note that the scope is the entire JSX open tag (<_components.dov>)
code.tsx:13:8 - error TS2604: JSX element type '_components.dov' does not have any construct or call signatures. 13 <_components.dov></_components.dov> ~~~~~~~~~~~~~~~
This is confusing. Indeed, _components.dov has no construct or call signatures, but neither does _components.div. This also seems to be the same issue as above. _components.dov is not a valid JSX signature.
I imagine this has to with ElementType vs IntrinsicElements, but as an end user, this really looks like a duplicate error. And the message is just not helpful.
Note that the scope is the JSX tag name (_components.dov)
code.tsx:14:20 - error TS2339: Property 'dav' does not exist on type '{ readonly div: "div"; readonly dov: "dov"; }'. 14 <_components.dav></_components.dav> ~~~
This makes sense. Note that the scope is the dav member expression.
code.tsx:14:38 - error TS2339: Property 'dav' does not exist on type '{ readonly div: "div"; readonly dov: "dov"; }'. 14 <_components.dav></_components.dav> ~~~
This is redundant repetition. The same error was reported for the open tags. Note that the scope is the dav member expression.
No errors are reported for the </_components.dov> closing tags
So far, we have 4 + 8 = 12 errors from the CI output. However, the editor originally reported 15. The remaining 3 errors are related to incorrectness of the closing tags that were originally mismatched. They can only appear as semantic errors if syntactic errors are produced.
Suggestions
I have a couple of suggestions to improve this situation:
- If a JSX open tag has an error, don’t repeat it for the closing tag.
- Never report
TS2339andTS2604. Make them mutually exclusive. - Improve the error message for
TS2604to clarify some strings are valid. - Narrow the scope of all JSX tag errors to the JSX name (
dov), not the entire element (<dov>). The scope of the entire element can become huge if props are involved.
Activity