TS2786 'Component' cannot be used as a JSX component

Viewed 17055

I have a React Typescript application that won't compile. Many components have a render method that is typed to return React.ReactNode or React.ReactElement. On compile, many errors similar to the following are reported:

TS2786: 'MessagesWidget' cannot be used as a JSX component.
 Its instance type 'MessagesWidget' is not a valid JSX element.
 The types returned by 'render()' are incompatible between these types.
 Type 'React.ReactNode' is not assignable to type 'import("/home/node/app/node_modules/@types/react-calendar/node_modules/@types/react/index").ReactNode'.

Why is the compiler expecting ReactNode as defined by the types bundled with react-calendar? I do have @types/react-dom installed as a dev dependency.

Other information that might be relevant:

  1. This project was compiling until a couple of days ago and there were no code changes when the compile started failing, so I suspect that a package update triggered this (even if that's not the root cause). The only dependencies that were updated in the time window when the compile started failing were @types/react and @types/react-dom. Rolling these packages back to an older version did not fix the issue, however.
  2. Changing my components render methods to return JSX.Element removes the compiler error, but there are third party components in the application where this is not possible.
5 Answers

I have a solution, it seems that there are a ton of breaking changes in the 18.0.1 type definitions.

Like you, I could not solve it by rolling back to earlier versions, but investigation lead me to discover that this was because 'react-router' among others was bringing in the '18.0.1' version.

to get around this, I added the following to my package.json

  "resolutions": {
    "@types/react": "17.0.14",
    "@types/react-dom": "17.0.14"
  },

Then I cleared my node-modules, and my package cache and then re-ran yarn to pull fresh packages.

The resolutions section is for yarn (which I use). and I think you can use 'overrides' instead of 'resolutions' if you are using NPM.

npm version should >= 8 https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides

and delete package-lock.json before npm i.

Error TS2786 often comes from a mismatch in @types/react.

When you have libraries that are dependent on a specific version of @types/react (i.e. v17.0.47) and you have other libraries working with a different major version of @types/react (i.e. v18.0.14), then this can cause compatibility issues when using React.ReactNode or JSX.Element. The type JSX.Element is usually returned by a React Function Component.

You can solve the problem by streamlining your dependencies on @types/react, so that these follow the same major version. You can find all libraries depending on @types/react in your project by executing npm explain @types/react (when a package-lock.json file is present) or yarn why @types/react (when a yarn.lock file is present).

In your specific case there seems to be a dependency from @types/react-calendar to @types/react. Your problem seems to be that there are other dependencies in your project using a different version of @types/react. Maybe you even have a direct dependency on @types/react where the exact version number is different from the @types/react version required by @types/react-calendar.

This can occur when returning children:

export const Component = ({ children }) => {
    //...do stuff
    return children
}

To fix, wrap in a fragment:

return <>{children}</>

I believe this is because children may be an array of elements and we are only allowed to return a single element. The usual message for this kind of error is:

JSX expressions must have one parent element.

The problem is because react-route v18 does not support react-virtualized and it should be downgraded.

So the simple way is to downgrade your route as below:

"@types/react": "17.0.0",
"@types/react-dom": "17.0.0"

Then, your app should work properly.

Related