Question

Understanding "JSX element type does not have any construct or call signatures" in React and TypeScript

typescriptreactjs

Question

In React with TypeScript, I wrote the following code:

function renderGreeting(Elem: React.Component<any, any>) {
  return <span>Hello, <Elem />!</span>;
}

TypeScript shows this error:

JSX element type 'Elem' does not have any construct or call signatures.

What does this error mean, and how should a component parameter be typed so it can be used as <Elem /> inside JSX?

Short Answer

By the end of this page, you will understand why TypeScript rejects some values in JSX, what "construct or call signatures" means, and how to correctly type a React component passed as a variable. You will also see the difference between a component instance, a component type, and a rendered React element.

Concept

In React, writing <Elem /> means "render the component stored in Elem". For TypeScript to allow that, Elem must be a component type that can be called like a function component or constructed like a class component.

The error:

JSX element type 'Elem' does not have any construct or call signatures.

means TypeScript looked at the type of Elem and concluded:

  • it is not callable like a function, and
  • it is not constructable like a class

So TypeScript cannot safely treat it as a JSX component.

In your example, React.Component<any, any> is the wrong type for Elem.

function renderGreeting(Elem: React.Component<any, any>) {
  return <span>Hello, <Elem />!</span>;
}

React.Component<any, any> describes a component instance object, not a component definition. JSX needs the definition/type of a component, not an already-created instance.

A better type is usually one of these:

  • React.ComponentType<P> — any React component that accepts props P
  • React.ElementType — any valid JSX element type, including components and intrinsic tags like 'div'

For a component with no props:

function renderGreeting(Elem: React.ComponentType) {
  return <span>Hello, <Elem />!</span>;
}

Or more explicitly:

function renderGreeting(Elem: React.ComponentType<{}>) {
  return <span>Hello, <Elem />!</span>;
}

This matters because TypeScript uses types to verify JSX correctness. If you pass the wrong kind of value, it catches the mistake before runtime.

Mental Model

Think of three different things:

  • Blueprint: the component definition itself, like MyButton
  • Built object: an instance created from that blueprint
  • Final output: the rendered element, like what JSX produces

When you write:

<MyButton />

React needs the blueprint, not the built object.

Your original type used React.Component, which is closer to the built object/instance idea. But JSX expects something it can use to create an element: a function component or class component type.

So the error is TypeScript saying:

"You gave me something that does not look like a component blueprint I can call or construct."

Take Quiz

Syntax and Examples

The most common fix is to type the parameter as React.ComponentType.

Component with no props

function renderGreeting(Elem: React.ComponentType) {
  return (
    <span>
      Hello, <Elem />!
    </span>
  );
}

Example usage:

const Name = () => <>Alice</>;

renderGreeting(Name);

Name is a function component, so TypeScript allows <Elem />.

Component with props

If the component needs props, include them in the type:

type UserProps = {
  name: string;
};

function renderGreeting(Elem: React.ComponentType<UserProps>) {
  return (
    <span>
      Hello, <Elem name="Alice" />!
    </span>
  );
}

Now TypeScript knows that Elem must accept a name prop.

Using React.ElementType

ElementType is broader:

function renderWrapper(Elem: React.ElementType) {
  return <Elem />;
}

This can accept:

  • React components
  • built-in tags like 'div'

Example:

renderWrapper("section");

Use ComponentType when you specifically mean a React component. Use ElementType when you also want strings like 'div', 'button', or 'span'.

What not to do

function renderGreeting(Elem: React.Component<any, any>) {
  return <Elem />;
}

This is incorrect because React.Component represents an instance type, not the component type used in JSX.

Step by Step Execution

Consider this example:

type Props = { name: string };

const UserName = ({ name }: Props) => <strong>{name}</strong>;

function renderGreeting(Elem: React.ComponentType<Props>) {
  return (
    <div>
      Hello, <Elem name="Sam" />
    </div>
  );
}

const result = renderGreeting(UserName);

Step by step

  1. Props is defined as:

    { name: string }
    
  2. UserName is a function component that accepts those props.

  3. renderGreeting expects Elem to be a React.ComponentType<Props>.

    • That means Elem must be a valid React component.
    • It must accept a prop object with a name string.
  4. renderGreeting(UserName) is valid because UserName matches that type.

  5. Inside the function, TypeScript sees:

    <Elem name="Sam" />
    

    and verifies:

    • Elem is renderable as JSX
    • name is required
    • name is a string
  6. If you forgot the prop:

    <Elem />
    

    TypeScript would report an error because name is required.

Why the original version fails

If Elem is typed as React.Component<any, any>, TypeScript treats it like an object instance. An object instance is not something JSX can invoke as a component type, so <Elem /> becomes invalid.

Real World Use Cases

Passing components as values is common in React applications.

Reusable layout components

A layout may receive a component to render inside a slot:

type SlotProps = { title: string };

function PageHeader(Header: React.ComponentType<SlotProps>) {
  return <Header title="Dashboard" />;
}

Route configuration

Many apps store component references in route definitions:

type Route = {
  path: string;
  component: React.ComponentType;
};

Render props and pluggable UI

Design systems and dashboards often allow users to supply custom components:

  • custom icon components
  • custom row renderers
  • custom form field renderers

Generic wrappers

A utility may accept a component and inject shared props:

function withUser<P>(Comp: React.ComponentType<P & { userId: string }>) {
  return (props: P) => <Comp {...props} userId="123" />;
}

In all of these cases, you must type the value as a component type, not a component instance.

Take Quiz

Real Codebase Usage

In real projects, developers usually use a few common patterns.

Accepting a component prop

type EmptyStateProps = {
  Illustration: React.ComponentType;
};

function EmptyState({ Illustration }: EmptyStateProps) {
  return (
    <div>
      <Illustration />
      <p>No data found.</p>
    </div>
  );
}

Guarding props with explicit component types

When a component requires props, developers encode that into the type:

type BadgeProps = { label: string };

type CardProps = {
  Badge: React.ComponentType<BadgeProps>;
};

This avoids runtime mistakes because TypeScript enforces the required props.

Using ElementType for "as" props

A common pattern in UI libraries is an as prop:

type BoxProps = {
  as?: React.ElementType;
};

function Box({ as: Component = "div" }: BoxProps) {
  return <Component />;
}

This works because ElementType can represent either:

  • a component, or
  • a tag name like 'div'

Early error detection

Correct typing helps catch issues such as:

  • missing props
  • invalid JSX usage
  • passing rendered elements instead of component references

That is why teams usually prefer ComponentType<Props> over loose any types.

Common Mistakes

1. Using React.Component instead of React.ComponentType

Broken code:

function renderGreeting(Elem: React.Component<any, any>) {
  return <Elem />;
}

Why it fails:

  • React.Component is an instance type
  • JSX needs a component type

Fix:

function renderGreeting(Elem: React.ComponentType) {
  return <Elem />;
}

2. Passing a rendered element instead of a component

Broken code:

const Name = () => <>Alice</>;
renderGreeting(<Name />);

Why it fails:

  • <Name /> is already a React element
  • the function expects the component itself: Name

Fix:

renderGreeting(Name);

3. Forgetting required props

Broken code:

type Props = { name: string };

function renderGreeting(Elem: React.ComponentType<Props>) {
  return <Elem />;
}

Why it fails:

  • Elem requires name

Fix:

function renderGreeting(Elem: React.ComponentType<Props>) {
  return <Elem name="Alice" />;
}

4. Using ElementType when you only want React components

React.ElementType also allows strings like 'div'.

If that is too broad, use:

React.ComponentType<Props>

instead.

5. Using any too early

This works but removes useful checking:

function renderGreeting(Elem: React.ComponentType<any>) {
  return <Elem whatever="oops" />;
}

Prefer explicit props whenever possible.

Comparisons

TypeWhat it representsCan be used as <Elem />?Typical use
React.Component<P, S>A class component instanceNoRarely used directly for JSX variables
React.ComponentType<P>Any React component type (function or class)YesBest choice when accepting a component
React.ElementTypeAny valid JSX element type, including 'div'YesUseful for as props or dynamic tags
JSX.ElementA rendered React elementNoReturn type of JSX expressions
React.ReactNodeAnything React can renderNoChildren, mixed renderable content

ComponentType vs ElementType

  • Use React.ComponentType<Props> when you want a real React component.
  • Use React.ElementType when you want either a component or a tag name.

Component type vs element

const MyComp = () => <div>Hello</div>; // component type
const element = <MyComp />;            // rendered element
  • MyComp can be used later as <Elem />
  • element cannot be used as <Elem /> because it is already the result
Take Quiz

Cheat Sheet

// Accept any React component with no props
function fn(Elem: React.ComponentType) {
  return <Elem />;
}

// Accept a React component with props
function fn(Elem: React.ComponentType<{ name: string }>) {
  return <Elem name="Alice" />;
}

// Accept a component OR intrinsic tag like 'div'
function fn(Elem: React.ElementType) {
  return <Elem />;
}

Quick rules

  • <Elem /> requires Elem to be a valid JSX element type
  • React.Component is not the right type for this case
  • React.ComponentType<Props> is the usual fix
  • React.ElementType is broader than ComponentType
  • Pass MyComponent, not <MyComponent />, when a function expects a component

Common meanings

  • component type: MyComponent
  • element: <MyComponent />
  • instance: internal object created for class components

Edge case

If the component requires props, include them in the generic type or TypeScript cannot properly validate JSX usage.

FAQ

What does "construct or call signatures" mean in TypeScript?

It means TypeScript expects a value that can be used like a function or class. JSX components must be callable as function components or constructable as class components.

Why does React.Component cause this error?

Because React.Component describes a component instance, not the component type that JSX needs to create an element.

Should I use React.ComponentType or React.ElementType?

Use React.ComponentType when you want a React component only. Use React.ElementType when you also want to allow strings like 'div' or 'button'.

What is the difference between MyComp and <MyComp />?

MyComp is the component itself. <MyComp /> is the rendered element created from it.

Can class components also use React.ComponentType?

Yes. React.ComponentType covers both function components and class components.

Why does TypeScript care about the props of Elem?

Because when you write <Elem ... />, TypeScript validates that the props you pass match what that component expects.

Is JSX.Element the right type for a component parameter?

No. JSX.Element is the result of rendering JSX, not a component definition you can later use as <Elem />.

Take Quiz

Mini Project

Description

Build a small greeting utility that accepts different React components and renders them inside a greeting message. This project demonstrates the difference between component types, rendered elements, and prop-aware typing in TypeScript.

Goal

Create a reusable function and component setup that safely accepts React components as arguments and renders them with the correct props.

Requirements

[ "Create one component that takes no props and one component that takes a name prop.", "Write one function that accepts a no-props component using the correct type.", "Write another function that accepts a component with typed props and renders it correctly.", "Demonstrate valid usage by passing component references, not rendered elements.", "Include one example using React.ElementType with an intrinsic tag like 'section'." ]

Take Quiz

Keep learning

Related questions

View more