Ashima
Ashima

Reputation: 4824

Typescript - Restrict passing valid prop to a React component

Is it possible to restrict passing a valid prop to a react component?

Example:

<SomeComponent primaryCTA={<Button size="small">Click here</Button} />

Now, in the code above, I want to user to NOT be able to provide size prop.

This is how type Props of SomeComponent look like

type SomeComponentProps = {
  primaryCTA: React.ReactElement<
     Exclude<ButtonProps, 'size'>,
     typeof Button>;
}

But, the code above doesn't work. You can still provide size prop to Button component inside SomeComponent.

Upvotes: 1

Views: 750

Answers (1)

Alex Wayne
Alex Wayne

Reputation: 187024

You can't restrict the type here because rendered JSX doesn't carry with it the type of the component that rendered it. This means that there is no type information to restrict:

const button = <Button size="small">foo</Button> // type: JSX.Element

Instead, it's usually best to let SomeComponent handle creating the button by exposing props about how to do that.

For example, if primaryCTA was typed as string, then in your SomeComponent rendering you could create the button:

function SomeComponent({ primaryCTA }: Props) {
  return <Button size="small-or-whatever">{primaryCTA}</Button>
}

Or you can make primaryCTA be the type of props that Button expects.

You can use React.ComponentProps<typeof Button> to get the prop types from the Button component, and then you can use Omit<Props, 'size'> to remove whatever you don't want to expose. Lastly, you can spread those props back into the button with <Button {...primaryCTA} />

Putting that together, you could do something like:

interface SomeComponentProps {
    primaryCTA: Omit<React.ComponentProps<typeof Button>, 'size'>
}

function SomeComponent({ primaryCTA }: SomeComponentProps) {
    return <>
        <div>Testing this component</div>
        <Button {...primaryCTA} size='small' />
    </>
}

// Usage of SomeComponent
<SomeComponent primaryCTA={{ color: 'red', children: 'click here!' }} />

Playground

Upvotes: 1

Related Questions