preact: [typescript] React.ReactElement type is not compatible with Preact and prevents interoperability with React
There is a type mismatch between React.ReactElement
and preact.VNode
that prevents usage of typescript/react code with typescript/preact.
While the code below compiles and works without an issue, Typescript typechecking fails.
Reproduction
import type React from 'react'
import { FunctionalComponent, h } from 'preact'
const ReactFCInterlop: React.FC = () => {
return <span>hello</span>
}
const Home: FunctionalComponent = () => {
return (
<div>
<ReactFCInterlop /> // this fails to typecheck
</div>
)
}
export default Home
This results in the following typescript error:
$ tsc
src/routes/home/index.tsx:11:14 - error TS2786: 'ReactFCInterlop' cannot be used as a JSX component.
Its return type 'ReactElement<any, any> | null' is not a valid JSX element.
Type 'ReactElement<any, any>' is missing the following properties from type 'Element': nodeName, attributes, children
11 <ReactFCInterlop />
~~~~~~~~~~~~~~~
Typescript config:
$ tsc --showConfig
{
"compilerOptions": {
"skipLibCheck": true,
"target": "es5",
"module": "esnext",
"allowJs": true,
"jsx": "preserve",
"jsxFactory": "h",
"noEmit": true,
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"files": [
"./src/components/app.tsx",
"./src/components/header/index.tsx",
"./src/routes/home/index.tsx",
"./src/routes/notfound/index.tsx",
"./src/routes/profile/index.tsx",
"./src/tests/header.test.tsx",
"./src/types.d.ts",
"./src/components/header/style.css.d.ts",
"./src/routes/home/style.css.d.ts",
"./src/routes/notfound/style.css.d.ts",
"./src/routes/profile/style.css.d.ts",
"./src/tests/declarations.d.ts"
],
"include": [
"src/**/*.tsx",
"src/**/*.ts"
]
}
Deps:
$ npm ls --depth 0 | grep preact
├── enzyme-adapter-preact-pure@2.2.3
├── jest-preset-preact@4.0.2
├── preact@10.4.8
├── preact-cli@3.0.1
├── preact-jsx-chai@3.0.0
├── preact-markup@2.0.0
├── preact-render-to-string@5.1.10
├── preact-router@3.2.1
Tested with Typescript: 4.0.2
/ 3.9.7
Expected Behavior
Preact should be able to interlope with components that use typescript and @types/react
. There a lot of components like that.
Workaround
This is a very dumb workaround, but it works:
// src/types.d.ts
import React from 'react'
declare global {
namespace React {
interface ReactElement {
nodeName: any
attributes: any
children: any
}
}
}
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 20
- Comments: 17 (7 by maintainers)
Commits related to this issue
- Exclude internal type definitions from generated package The types defined in `index.d.ts` are only for use by the package's internal code and tests. There is nothing there that should be published. ... — committed to preactjs/enzyme-adapter-preact-pure by robertknight 4 years ago
- Exclude internal type definitions from generated package Move Preact 8 VNode extensions from `index.d.ts` to `internal.d.ts` to avoid shipping them with the package and causing type checking errors f... — committed to preactjs/enzyme-adapter-preact-pure by robertknight 4 years ago
- Exclude internal type definitions from generated package Remove Preact 8 VNode extensions from `index.d.ts` as these cause type checking errors for Preact 10 users. See https://github.com/preactjs/p... — committed to preactjs/enzyme-adapter-preact-pure by robertknight 4 years ago
May I suggest that this issue is marked as a documentation issue by adding @Svampen fix to the Typescript Configuration section in the docs.
@Svampen suggests above adding the following to
tsconfig.json
:The paths are relative to the
baseUrl
so if you change that, which you might, you must change the paths accordingly, for example, if you have"baseUrl":"./src"
then your paths would start with../node_modules
(double-dot).You have no control over what and how other imported packages and their dependencies reference and cause
@types/react
to be installed. Any potential developer who adds@types/react
as a dependency instead of apeerDependency
in theirpackage.json
will cause the same issue. It might be Enzyme or, as it is my case, a dependency of a dependency ofreact-bootstrap
but it might be anything else in the future, you have no control over that.Whichever way it gets loaded, once it is, you are in trouble. By equating the paths to
react
andreact-dom
topreact/compat
throughtsconfig.json
, it doesn’t matter which dependent package imports those definitions, it won’t even look at@types/react
even if it does get installed intonode_modules
, it will simply be ignored.I had the similar issue in which I’m using a react component in which one of the props allow for a React.ReactElement<any> in which a VNode isn’t matching. After a lot of googling I found one solution that worked for me which was to add the following to my tsconfig.json:
I was pretty sure that having the following in webpack would do the same (but maybe that wasn’t working in my setup):
This has been added to the dos in https://github.com/preactjs/preact-www/pull/850 thank you @satyam
@marvinhagemeister Right. I posted not to get help, but to point out how
@types/react
may not have working types in the first place. Therefore, the original issue may not be Preact’s fault, as Preact can’t interop with broken declarations.@colin-ggd - Would you be able to help me test https://github.com/preactjs/enzyme-adapter-preact-pure/pull/124? It looks to me like all of the type definitions in
enzyme-adapter-preact-pure/index.d.ts
are in fact only internal types needed when building the package. If so they can simply be excluded.Edit: Nevermind - it is not ready yet. I rushed this. Some other changes are required.