Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 220884

What does the error "JSX element type '...' does not have any construct or call signatures" 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?

Upvotes: 423

Views: 556350

Answers (24)

pmiranda
pmiranda

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

CenterADiv
CenterADiv

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

Haroen Viaene
Haroen Viaene

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

H. Almidan
H. Almidan

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

Adi Dasler
Adi Dasler

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

Kirk Strobeck
Kirk Strobeck

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

Nivethan
Nivethan

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

Sebastian
Sebastian

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

Gabriel Arghire
Gabriel Arghire

Reputation: 2360

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

Upvotes: -6

aprilmintacpineda
aprilmintacpineda

Reputation: 1274

import React from 'react';

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

Upvotes: 4

Zargold
Zargold

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

Zeeshan Ahmad
Zeeshan Ahmad

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

leloctai
leloctai

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

Akash Singh
Akash Singh

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

Ryan Cavanaugh
Ryan Cavanaugh

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

snowyBunny
snowyBunny

Reputation: 445

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

Upvotes: 5

jmunsch
jmunsch

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

Mark Kalinovits
Mark Kalinovits

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

Nickofthyme
Nickofthyme

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

Warao
Warao

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

ArchNoob
ArchNoob

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

Michael
Michael

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

Eduard
Eduard

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

Luke
Luke

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

Related Questions