Proper TypeScript type for creating JSX element from string

Tags: , ,



I have a component that I want to default to being rendered as an h2. I’d like the consumer to be able to specify a different element if they desire. The code below results in the error:

TS2604 - JSX element type 'ElementType' does not have any construct or call signatures

I think I understand why it fails, TS is expecting to render a React node. For clarity, React is able to render elements referenced as strings as long as the variable begins with a capital letter (this being a JSX requirement). I’ve done this before successfully in vanilla JS + React, I just don’t know how to satisfy TypeScript.

How can I get TypeScript to render this without resorting to elementType?: any

import React, {ReactNode} from 'react'

interface Props {
    children: ReactNode;
    elementType?: string;
}

export default function ({children, elementType: ElementType = 'h2'}: Props): JSX.Element {
    return (
        <ElementType>{children}</ElementType>
    );
}

Answer

First, a bit about JSX. It is just a syntactic sugar for React.createElement, which is a JavaScript expression.

With this knowledge in mind, now let’s take a look at why TypeScript complains. You define elementType as string, however, when you actually use it, it becomes a JavaScript expression. string type of course doesn’t have any construct or call signature.

Now we know the root cause. In React, there is a type called FunctionComponent. As you can guess, it is a function expression, which is what we want. So you can define elementType as string | FunctionComponent. This should make TypeScript happy 🙂

FYI: the recommended way to define prop typing is by doing this:

const MyComponent: FunctionComponent<Props> = (props) => {}


Source: stackoverflow