问题
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?
回答1:
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>;
}
回答2:
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>;
}
回答3:
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")
回答4:
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!'
}
});
回答5:
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.
回答6:
In my case I was missing new
inside the type definition.
some-js-component.d.ts
file:
import * as React from "react";
export default class SomeJSXComponent extends React.Component<any, any> {
new (props: any, context?: any)
}
and inside the tsx
file where I was trying to import the untyped component:
import SomeJSXComponent from 'some-js-component'
...inside render()
return (
<React.Fragment>
<SomeJSXComponent withProps={asdf} />
</React.Fragment>
);
回答7:
When declaring React class component, use React.ComponentClass
instead of React.Component
then it will fix the ts error.
来源:https://stackoverflow.com/questions/31815633/what-does-the-error-jsx-element-type-does-not-have-any-construct-or-call