Borislav Hadzhiev
Sun Apr 17 2022·3 min read
Photo by Autri Taheri
The error "JSX element type does not have any construct or call signatures"
occurs when we try to pass an element or react component as props to another
component but type the prop incorrectly. To solve the error, use the
React.ElementType
type.
Here is an example of how the error occurs.
import React from 'react'; interface Props { comp: JSX.Element; } const Wrapper: React.FunctionComponent<Props> = props => { const {comp: Comp} = props; // ⛔️ JSX element type 'Comp' does not have any construct or call signatures.ts(2604) return ( <div> <Comp name="James" /> </div> ); }; const App: React.FunctionComponent = () => { const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>; return ( <div> <Wrapper comp={heading} /> </div> ); }; export default App;
We are trying to pass a React component as a prop to the Wrapper
component,
but have typed it as JSX.Element
.
To solve the error, we have to type the prop as React.ElementType
.
import React from 'react'; interface Props { comp: React.ElementType; // 👈️ type it as React.ElementType } const Wrapper: React.FunctionComponent<Props> = props => { // 👇️ component names must start with capital letter const {comp: Comp} = props; return ( <div> <Comp name="James" /> </div> ); }; const App: React.FunctionComponent = () => { // 👇️ takes a name prop const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>; return ( <div> <Wrapper comp={heading} /> </div> ); }; export default App;
Note that React.ElementType
can be passed a generic for the type of the props
that the element expects.
In this example we would have to pass it an object that has a name
property of
type string
because that's the prop the heading component takes.
import React from 'react'; interface Props { // ✅ explicitly type props comp takes comp: React.ElementType<{name: string}>; } const Wrapper: React.FunctionComponent<Props> = props => { // 👇️ component names must start with capital letter const {comp: Comp} = props; return ( <div> <Comp name="James" /> </div> ); }; const App: React.FunctionComponent = () => { const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>; return ( <div> <Wrapper comp={heading} /> </div> ); }; export default App;
Now we explicitly typed the props the comp
element takes when used. This helps
us leverage our IDE for autocompletion when passing props to the component.
We could also use the React.ComponentType
but then we are required to type the
props.
import React from 'react'; interface Props { // 👇️ now using React.ComponentType 👇️ comp: React.ComponentType<{name: string}>; } const Wrapper: React.FunctionComponent<Props> = props => { // 👇️ component names must start with capital letter const {comp: Comp} = props; return ( <div> <Comp name="James" /> </div> ); }; const App: React.FunctionComponent = () => { const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>; return ( <div> <Wrapper comp={heading} /> </div> ); }; export default App;
The generic in React.ComponentType
does not default to the any
type, so we
are required to explicitly type the props.
Note that if you pass a JSX element as props to a component and not an actual
component, then JSX.Element
is the right type.
import React from 'react'; interface Props { // 👇️ using JSX.Element type comp: JSX.Element; } const Wrapper: React.FunctionComponent<Props> = props => { const {comp: Comp} = props; // 👇️ use as {Comp} return <div>{Comp}</div>; }; const App: React.FunctionComponent = () => { const Heading = ({name}: {name: string}) => <h2>Hello {name}</h2>; // 👇️ we are passing an actual JSX element // because we didn't pass it as comp={Heading} return ( <div> <Wrapper comp={<Heading name="James" />} /> </div> ); }; export default App;
We typed the comp
prop as JSX.Element
because we are passing an actual JSX
element (not a component) to the Wrapper
component.
We are passing a JSX element because we passed the prop as comp={<Heading />}
instead of comp={(props) => <h2>Hello world</h2>}
.
We shouldn't try to use the JSX element as a component in our Wrapper
component, e.g. don't do <Comp />
, instead do {Comp}
.
We haven't passed an actual component as a prop, we passed a JSX element, so it shouldn't be used as a component.
If none of the previous suggestions helped, try to update the versions of your React typings by running the following commands.
# 👇️ with NPM npm install react@latest react-dom@latest npm install --save-dev @types/react@latest @types/react-dom@latest # ---------------------------------------------- # 👇️ with YARN yarn add react@latest react-dom@latest yarn add @types/react@latest @types/react-dom@latest --dev