“Pick one or other” props in React with TypeScript

Andre Simamora
eFishery Engineering
4 min readOct 27, 2022
Photo by Vinicius “amnx” Amano on Unsplash

Many times we use the same component for different purposes. That’s what I’m doing when I’m working in my office, eFishery. But, have you ever faced a case when creating a component there is a condition where there are two props, one of which is required but not both? This article aims to provide an answer to overcome this condition.

One day I was given the task to create a success page that has the same design but different purposes, like the following designs:

Success Page with Action Buttons and Redirect Action

What’s different?

  • In the first design, the user needs to click the button first before being redirected to a certain page
  • In the second design, the user is automatically redirected to a certain page after a few seconds

Of course, we will make it in the same component based on the two designs above, right?

Let’s code!

To create a component according to the design above, in general, we will do it like the code below:

As you can see from the code above, we will be using the actionButtons prop to handle the first design and the redirectAction prop to handle the second design. And we will make both of them optional because both props can’t be set together.

Are we doing the right thing?

The problem: Both props may NOT be set

If we make both props optional, then there is a possibility that they are not set.

As we can see, there is no error message when one of the props we need is not set. We need it though, right?

The solution: Redesign the type

The solution we can do to solve this problem is to redesign the SuccessScreenProps interface by using the union and never types when extending the type, like the following code:

interface SuccessScreenContent {
title: string;
description: string;
}
interface SuccessScreenWithButtons extends SuccessScreenContent {
actionButtons: ActionButtons;
redirectAction?: never;
}
interface SuccessScreenWithRedirect extends SuccessScreenContent {
actionButtons?: never;
redirectAction: RedirectAction;
}
type SuccessScreenProps = SuccessScreenWithButtons | SuccessScreenWithRedirect;

Firstly, we define a common interface, which can be used for both conditions.

Secondly, we define an interface specifically to handle the two different conditions. As you can see, we defined the same interface, but what we don’t need we will make it optional and use the never type.

The never type represents values which are never observed. — TypeScript

Lastly, to avoid the possibility of unset props, we’ll combine them using union types, which can help determine which props are valid between the two conditions.

Now the component can accept any of the required props but not both.

Success page with action buttons

As per our redesigned interface above, to create a success page with action buttons, we need to set common props and actionButtons like the following:

Code for success page with action buttons

No error message is displayed, right? Let’s try to create a success page with redirect action.

Success page with redirect action

The code is similar to the previous condition example. But for the current condition, we replaceactionButtons with redirectAction, like the following:

Code for success page with redirect action

So far so good, right?

How about we try not to set the props for both conditions above? Or how about we try to set both props?

“Pick one or other” props!

First of all, let’s try not to set props for both conditions.

Both props are not set

Oops, as you can see, we’re getting an error message because we didn’t set either actionButtons or redirectAction.

How about we try to set the two props required by the two conditions?

Both props are set

Turns out we still get the error message. This is because the component cannot receive both props at the same time.

Conclusion

With TypeScript, you can create components with dynamic props which can help you define the correct props for your components and provide a better React coding experience.

References

--

--