1

How can I type a prop that accepts ComponentType or a string?

Suppose the following code.

interface MyComponentProps {
    Component: React.ComponentType
}
const MyComponent: React.FC<PropsWithChildren<MyComponentProps>> = ({Component}) => {
    return <Component>{children}</Component>
}
<MyComponent
    Component="span"
/>

Trying this in TS gives the following error.

Type 'string' is not assignable to type 'ComponentType<{}> | undefined'.

How can I dynamically render a native html tag using JSX?

0

1 Answer 1

3

In terms of react and javascript, your code is correct. The issue here is the types. The string "span" is not a ComponentType. The type you want for Component is React.ElementType. If you check out the definition of ElementType it includes all of the intrinsic jsx elements or a component type.

You can come to this conclusion by yourself by rendering a <span></span> and hovering over or clicking through to the span keyword. You'll see the type is JSX.IntrinsicElements.span. If you click through you can see that IntrinsicElements includes all the html elements. I did a search to see where that type was being used which led me to the React.ElementType

Updated code:

interface MyComponentProps {
    Component: React.ElementType
}
const MyComponent: React.FC<PropsWithChildren<MyComponentProps>> = ({Component}) => {
    return <Component>{children}</Component>
}
<MyComponent
    Component="span"
/>

Side note: React.FC might not be the best approach anymore. Instead it seems to be preferable to just assign a type to the props directly:

const MyComponent = ({Component}: PropsWithChildren<MyComponentProps>) => {
    return <Component>{children}</Component>
}

More on that here if you're interested: https://github.com/facebook/create-react-app/pull/8177

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot for outlining how to reach your conclusion. This is the answer I was hoping for. Very insightful read about React.FC. Much appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.