The text starts here~
Overview
"JSX element type does not have any construct or call signatures" error is generated when we try to pass an element or react component as an attribute to another component, but the type of the attribute is declared wrong. To resolve this error, the type React.ElementType
can be used.
Here is an example to show how the error occurs.
// App.tsx
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 tried to pass a React component as a property to the Wrapper
component, but we declared the type of that React component as JSX.Element
.
React.ElementType
To resolve the error, declare the property's type as React.ElementType
.
// App.tsx
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 pass a generic for the type of attribute expected by the element.
In this example, we have to pass it an object with a name
property of type String, because that's the heading
adf37a630bc83a33cb7d32b9f386e40d--- property that the component receives.
// App.tsx
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 declare the type of attribute that the element accepts when it is used comp
. This helps us take advantage of the IDE's autocomplete feature when passing properties to the component.
We could also use React.ComponentType
, but then we need to declare the type on the property.
// App.tsx
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;
Generic types in React.ComponentType
803dc3394bbce2db39ba2297272632f7--- cannot default to any
type, so we need to explicitly declare the type of the property.
Passing JSX elements
If you need to pass a JSX element as an attribute to a component, and it's not really a component, then using the JSX.Element
type is correct.
// App.tsx
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 declared the type of the comp
property as JSX.Element
because we passed a real JSX element (not a component) to the Wrapper
component.
We're passing a JSX element because we're passing comp={<Heading />}
as an attribute, not comp={(props) => <h2>Hello world</h2>}
.
Note that in the first case we are passing a JSX element attribute. And in the second case, we're passing a function that returns a JSX element (a functional component).
In Wrapper components, we should not try to use JSX elements as components. For example, instead of writing <Comp />
, write {Comp}
.
We're not passing a real component as a property, we're passing a JSX element, so it shouldn't be used as a component.
update type package
If none of the previous suggestions helped, try updating your React type version by running the following command.
# 👇️ 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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。