Reputation: 220884
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?
Upvotes: 423
Views: 556350
Reputation: 8420
Just 2 cents. In a Interface of many props, I had as optional the Component that was marked with the error. It wasn't necessary that "?", I removed and the error disappeared.
Upvotes: 0
Reputation: 71
For me another syntax works:
interface ButtonBarProps {
startIcon: React.JSX.Element;
endIcon: React.JSX.Element;
}
// This doesnt work
export defaut function ButtonBar (props: ButtonBarProps) {
const StartIcon = props.startIcon as React.JSXElement
const EndIcon = props.endIcon as React.JSXElement
return (<div>
<StartIcon />
<EndIcon />
</div>)
}
// This works
export defaut function ButtonBar (props: ButtonBarProps) {
return (<div>
{props.startIcon}
{props.endIcon}
</div>)
}
Upvotes: 0
Reputation: 1360
There's another case in which this error could show up, and that's when you have a union between two types with a different generic, like this:
function A<T extends 0>(props: { t: T }) {
return <></>
}
function B<T extends 1>(props: { t: T }) {
return <></>
}
const C = Math.random() > 0.5 ? A : B;
<C t={2} />
To remedy this, make sure the base of the generic is the same:
function A<T extends number>(props: { t: T }) {
return <></>
}
function B<T extends number>(props: { t: T }) {
return <></>
}
const C = Math.random() > 0.5 ? A : B;
<C t={2} />
Here's a typescript playground link explaining that situation as well.
Upvotes: 0
Reputation: 518
In your case
function renderGreeting(Elem: React.ElementType) {
return <span>Hello, <Elem />!</span>;
}
would fix it (note React.ElementType
type).
I had the same error, but in my case, I forgot to add the parameter parenthesis to my element.
So it was like
const SomeElement = (<div> ... </div>)
but it should've been
const SomeElement = () => (<div> ... </div>)
Upvotes: 2
Reputation: 528
If your problem is react-monaco-editor, then try:
Before:
import MonacoEditor from 'react-monaco-editor';
Solution (After):
import MonacoEditor from 'react-monaco-editor/src/index';
The problem is the wrong way of importing.
Error tag: JSX element type does not have any construct or call signatures.
Upvotes: 0
Reputation: 18559
Use React.ElementType
See https://github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019
Answer is too short, so, lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus cursus dui vel consequat gravida. In ut tortor porttitor, maximus lectus ut, lacinia magna. Mauris vel elementum urna. Quisque arcu est, congue in urna quis, rhoncus interdum ante. Vivamus vel ornare neque. In hac habitasse platea dictumst. Curabitur egestas rhoncus lectus eu eleifend.
Upvotes: -3
Reputation: 3589
If you are using a Functional Component and passing a component as prop, for me the solution was changing React.ReactNode to React.ElementType
interface Props{
GraphComp: React.ElementType
}
const GraphCard:React.FC<Props> = (props) => {
const { GraphComp } = props;
return (
<div> <GraphComp /> </div>
)
}
Upvotes: 63
Reputation: 3594
If you really don't care about props then the widest possible type is React.ElementType
.
This would allow passing native dom elements as string. React.ElementType
covers all of these:
renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
render() {
return 'Hello, World!'
}
});
Upvotes: 22
Reputation: 2360
Here is an example to use TSX:
const SomeMadeComponent = (props: { someText: string }) => {
const { someText} = props;
return (
<div>
<p>{someText}</p>
</div>
);
};
And you use it like a normal component:
<SomeMadeComponent someText='Place your text here' />
Upvotes: -6
Reputation: 1274
import React from 'react';
function MyComponent (
WrappedComponent: React.FunctionComponent | React.ComponentClass
) {
return (
<Wrapper>
<WrappedComponent />
</Wrapper>
);
}
Upvotes: 4
Reputation: 2092
Looks like there is now a special new TypeScript type to address the need of this question: JSXElementConstructor
. If you are letting someone pass in the constructor to an unknown ReactElement rather than an instance of that ReactElement this is the correct type to pass.
const renderGreeting = (Elem: JSXElementConstructor<any>) => {
return <span>Hello, <Elem />!</span>;
}
This is equivalent to the above selected correct answer because: using <Elem />
in JSX (aka wrapping a capital case variable with angle brackets) is equivalent to calling the constructor of a JSX Element with the new
keyword.
Upvotes: 16
Reputation: 5634
If you are passing functional component as props to another component use following:
import React from 'react';
type RenderGreetingProps = {
element: React.FunctionComponent<any>
};
function RenderGreeting(props: RenderGreetingProps) {
const {element: Element} = props;
return <span>Hello, <Element />!</span>;
}
Upvotes: 44
Reputation: 311
This is question the first result when I search for the error, so I would like to share the solution in my particular case:
The library I'm using look like this:
export { default as Arc } from './shapes/Arc';
I imported it incorrectly, which cause the error:
import Arc from "@visx/shape";
What it should be is
import { Arc } from "@visx/shape";
Upvotes: 13
Reputation: 557
I solved it by making use of Type Assertions before exporting the component. TypeScript wasn't able to identify after composing it using redux 'compose' therefore I divided props types into IParentProps and IProps and use IParentProps while doing Type Assertions
import { compose } from 'react-redux'
import HOC1 from 'HOCs/HOC1'
import HOC2 from 'HOCs/HOC2'
type IParentProps = {}
type IProps = {}
const Component: React.FC<IProps & IParentProps> = React.memo((props) => {
return <SomeComponent {...props}/>
})
return compose(HOC1,HOC2)(Component) as React.FunctionComponent<IParentProps>
Upvotes: -1
Reputation: 220884
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 is 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>;
}
Upvotes: 397
Reputation: 445
When declaring React Class component, use React.ComponentClass
instead of React.Component
then it will fix the ts error.
Upvotes: 5
Reputation: 24089
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'
const NewComp = ({ asdf }: NewProps) => <SomeJSXComponent withProps={asdf} />
Upvotes: 2
Reputation: 41
You can use
function renderGreeting(props: {Elem: React.Component<any, any>}) {
return <span>Hello, {props.Elem}!</span>;
}
However, does the following work?
function renderGreeting(Elem: React.ComponentType) {
const propsToPass = {one: 1, two: 2};
return <span>Hello, <Elem {...propsToPass} />!</span>;
}
Upvotes: 1
Reputation: 4327
As @Jthorpe alluded to, ComponentClass
only allows either Component
or PureComponent
but not a FunctionComponent
.
If you attempt to pass a FunctionComponent
, typescript will throw an error similar to...
Type '(props: myProps) => Element' provides no match for the signature 'new (props: myProps, context?: any): Component<myProps, any, any>'.
However, by using ComponentType
rather than ComponentClass
you allow for both cases. Per the react declaration file the type is defined as...
type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
Upvotes: 10
Reputation: 1105
The following worked for me: https://github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019 I fix it by doing something like this:
const Component = (isFoo ? FooComponent : BarComponent) as React.ElementType
Upvotes: 77
Reputation: 4126
In my case, I was using React.ReactNode
as a type for a functional component instead of React.FC
type.
In this component to be exact:
export const PropertiesList: React.FC = (props: any) => {
const list:string[] = [
' Consequat Phasellus sollicitudin.',
' Consequat Phasellus sollicitudin.',
'...'
]
return (
<List
header={<ListHeader heading="Properties List" />}
dataSource={list}
renderItem={(listItem, index) =>
<List.Item key={index}> {listItem } </List.Item>
}
/>
)
}
Upvotes: 4
Reputation: 2955
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")
Upvotes: 46
Reputation: 9165
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.
Upvotes: 15
Reputation: 14128
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>;
}
Upvotes: 97