“Pick one or other” props in React with TypeScript
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:
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:
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:
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.
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?
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
- TypeScript docs → https://www.typescriptlang.org/docs
- Conditional Props With TypeScript → https://levelup.gitconnected.com/conditional-props-with-typescript-78590139aa39