0

Let’s say I have a <Button /> component that can take two sets of props:

type CommonProps = {
  disabled?: boolean
  // ... other “normal” props here
}

type Props =
  | (CommonProps & { action: () => void })
  | (CommonProps & { href: string })

So Button can be used either like <Button action={() => {}} /> or <Button href="..." /> (each time with an optional disabled prop).

const Button = ({ action, disabled, href }) => {
  return // ...
}

Written like this, TypeScript complains about the destructured props in the component function argument, because action and href never co-occur. Understandable. But written like this:

type Props =
  | (CommonProps & { action: () => void; href: void })
  | (CommonProps & { action: void; href: string })

TS would complain about the <Button /* ... */ /> component not being passed an action={undefined} or href={undefined} prop.

So how would one go about typing a component with props that must not co-occur? What I’m looking for is something like

type Props = {
  action?: () => void
  href?: string
}

but without the possibility of both props being null or non-null at the same time, so that we can write for example <Button href="..." /> but not <Button action={() => {}} href="..." />.

Thanks for your advice!

Bart
  • 1,600
  • 1
  • 13
  • 29
  • did you try something like `action?: ButtonProps['href'] extends undefined ? () => void : undefined` same logic for href, although dynamically with jsx I dunno if will be picked up correctly. Why not using a single prop and checking the type you do the corresponding actions? – quirimmo Jan 11 '20 at 16:29
  • 1
    Maybe take a look here: https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types – quirimmo Jan 11 '20 at 16:35
  • Using the same aproach as here I think is what you want: https://stackoverflow.com/questions/59601795/checking-for-union-type – Titian Cernicova-Dragomir Jan 11 '20 at 16:47

0 Answers0