What does the error "JSX element type '...' does not have any construct or call signatures" mean?

ReactjsTypescript

Reactjs Problem Overview


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?

Reactjs Solutions


Solution 1 - Reactjs

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>;
}

Solution 2 - Reactjs

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>;
}

Solution 3 - Reactjs

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")

Solution 4 - Reactjs

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

Solution 5 - Reactjs

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>;
}

Solution 6 - Reactjs

If you are using a Functional Component and passing a component as props, 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>
  )
}

Solution 7 - Reactjs

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!'
   }
});

Solution 8 - Reactjs

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.

Solution 9 - Reactjs

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.

Solution 10 - Reactjs

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>

Solution 11 - Reactjs

When declaring React Class component, use React.ComponentClass instead of React.Component then it will fix the ts error.

Solution 12 - Reactjs

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";

Solution 13 - Reactjs

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>
      }
    />
  )
}

Solution 14 - Reactjs

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} />

Solution 15 - Reactjs

import React from 'react';

function MyComponent (
  WrappedComponent: React.FunctionComponent | React.ComponentClass
) {
  return (
    <Wrapper>
      <WrappedComponent />
    </Wrapper>
  );
}

Solution 16 - Reactjs

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>;
}

Solution 17 - Reactjs

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>

Solution 18 - Reactjs

It is because of syntax

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' />

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRyan CavanaughView Question on Stackoverflow
Solution 1 - ReactjsRyan CavanaughView Answer on Stackoverflow
Solution 2 - ReactjsLukeView Answer on Stackoverflow
Solution 3 - ReactjsMichaelView Answer on Stackoverflow
Solution 4 - ReactjsWaraoView Answer on Stackoverflow
Solution 5 - ReactjsziishanedView Answer on Stackoverflow
Solution 6 - ReactjsNivethanView Answer on Stackoverflow
Solution 7 - ReactjsepsilonView Answer on Stackoverflow
Solution 8 - ReactjsZargoldView Answer on Stackoverflow
Solution 9 - ReactjsEduardView Answer on Stackoverflow
Solution 10 - ReactjsNickofthymeView Answer on Stackoverflow
Solution 11 - ReactjssnowyBunnyView Answer on Stackoverflow
Solution 12 - ReactjsleloctaiView Answer on Stackoverflow
Solution 13 - ReactjsArchNoobView Answer on Stackoverflow
Solution 14 - ReactjsjmunschView Answer on Stackoverflow
Solution 15 - ReactjsaprilmintacpinedaView Answer on Stackoverflow
Solution 16 - ReactjsMark KalinovitsView Answer on Stackoverflow
Solution 17 - ReactjsAkash SinghView Answer on Stackoverflow
Solution 18 - ReactjsGabriel ArghireView Answer on Stackoverflow