Question
Understanding "JSX element type does not have any construct or call signatures" in React and TypeScript
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 propsPReact.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."
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
-
Propsis defined as:{ name: string } -
UserNameis a function component that accepts those props. -
renderGreetingexpectsElemto be aReact.ComponentType<Props>.- That means
Elemmust be a valid React component. - It must accept a prop object with a
namestring.
- That means
-
renderGreeting(UserName)is valid becauseUserNamematches that type. -
Inside the function, TypeScript sees:
<Elem name="Sam" />and verifies:
Elemis renderable as JSXnameis requirednameis a string
-
If you forgot the prop:
<Elem />TypeScript would report an error because
nameis 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.
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.Componentis 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:
Elemrequiresname
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
| Type | What it represents | Can be used as <Elem />? | Typical use |
|---|---|---|---|
React.Component<P, S> | A class component instance | No | Rarely used directly for JSX variables |
React.ComponentType<P> | Any React component type (function or class) | Yes | Best choice when accepting a component |
React.ElementType | Any valid JSX element type, including 'div' | Yes | Useful for as props or dynamic tags |
JSX.Element | A rendered React element | No | Return type of JSX expressions |
React.ReactNode | Anything React can render | No | Children, mixed renderable content |
ComponentType vs ElementType
- Use
React.ComponentType<Props>when you want a real React component. - Use
React.ElementTypewhen 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
MyCompcan be used later as<Elem />elementcannot be used as<Elem />because it is already the result
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 />requiresElemto be a valid JSX element typeReact.Componentis not the right type for this caseReact.ComponentType<Props>is the usual fixReact.ElementTypeis broader thanComponentType- 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 />.
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'." ]
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.