Skip to content

Instantly share code, notes, and snippets.

@brian-mcallister-lab49
Last active December 17, 2020 11:02
Show Gist options
  • Save brian-mcallister-lab49/02c43693d5251daa6e0e7335bed950e2 to your computer and use it in GitHub Desktop.
Save brian-mcallister-lab49/02c43693d5251daa6e0e7335bed950e2 to your computer and use it in GitHub Desktop.
TIL-Lab49/Exclusive React props with TypeScript.

It's not uncommon to have a React component that takes props where some of those props are mutually exclusive. Let's imagine a case where we have a Button component. We want our button to allow for the following possibilities:

  1. The button has text.
  2. The button has text and an icon.
  3. The button has an icon, but no text.

An initial implementation might look like:

const Button = ({ text, icon }: { text?: string; icon?: string }) => {
  // Handle button rendering here...
};

...but that will allow you to render the component like this: <Button /> with no errors, which is not ideal. You need to provide at least something to render!

We can solve this by using Discriminated Unions, but the non-obvious part is how we'll be using never to allow TypeScript to actually do the discrimination. If we implement this:

type WithText = {
    text: string;
    icon?: string;
}

type WithOnlyIcon = {
    text?: never; // <-- This is the important bit.
    icon: string;
}

type Props = WithText | WithOnlyIcon;

const Button = ({ text, icon }: Props) => {
  // Handle button rendering here...
};

Now, you'll get a TypeScript error if you try to render a Button with no icon and no text!

Here's a playground to explore this further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment