I wrote some code:
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
I'm getting an error:
JSX element type
Elem
does not have any construct or call signatures
What does it mean?
I wrote some code:
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
I'm getting an error:
JSX element type
Elem
does not have any construct or call signatures
What does it mean?
This is a confusion between constructors and instances.
Remember that when you write a component in React:
class Greeter extends React.Component<any, any> {
render() {
return <div>Hello, {this.props.whoToGreet}</div>;
}
}
You use it this way:
return <Greeter whoToGreet='world' />;
You don't use it this way:
let Greet = new Greeter();
return <Greet whoToGreet='world' />;
In the first example, we're passing around Greeter
, the constructor function for our component. That's the correct usage. In the second example, we're passing around an instance of Greeter
. That's incorrect, and will fail at runtime with an error like "Object is not a function".
The problem with this code
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
is that it's expecting an instance of React.Component
. What you want a function that takes a constructor for React.Component
:
function renderGreeting(Elem: new() => React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
or similarly:
function renderGreeting(Elem: typeof React.Component) {
return <span>Hello, <Elem />!</span>;
}
If you want to take a component class as a parameter (vs an instance), use React.ComponentClass
:
function renderGreeting(Elem: React.ComponentClass<any>) {
return <span>Hello, <Elem />!</span>;
}
When I'm converting from JSX to TSX and we keep some libraries as js/jsx and convert others to ts/tsx I almost always forget to change the js/jsx import statements in the TSX\TS files from
import * as ComponentName from "ComponentName";
to
import ComponentName from "ComponentName";
If calling an old JSX (React.createClass) style component from TSX, then use
var ComponentName = require("ComponentName")
If you really don't care about props then the widest possible type is React.ReactType
.
This would allow passing native dom elements as string. React.ReactType
covers all of these:
renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
render() {
return 'Hello, World!'
}
});
If you are using material-ui, go to type definition of the component, which is being underlined by TypeScript. Most likely you will see something like this
export { default } from './ComponentName';
You have 2 options to resolve the error:
1.Add .default
when using the component in JSX:
import ComponentName from './ComponentName'
const Component = () => <ComponentName.default />
2.Rename the component, which is being exported as "default", when importing:
import { default as ComponentName } from './ComponentName'
const Component = () => <ComponentName />
This way you don't need to specify .default
every time you use the component.