Conditionally Rendering React Components in TypeScript
When creating a new React component, we sometimes ran into a situation whereby we would like to conditionally render one component or the other based on the given React properties. In these situation, how can we effectively type the React component with TypeScript? 🤔
Thankfully, TypeScript comes with some features that we could make use of to type these components. We'll be exploring a naive and a more effective approach in this article.
Using the optional operator (?
) . Referring to the example below, when item1
property exist, then render ComponentA
else render ComponentB
. This works as expected. However, it's not a good approach.
- What if you have more props (
item3
,item4
,item5
,item-n
),GeneralType
will quickly become messy. - It's not obvious which property that you have defined in the
GeneralType
belongs toComponentA
orComponentB
.
type GeneralType = {
item1?: string;
item2: number;
};
const GeneralComponent = (props: GeneralType) => {
if (props.item1) {
return <ComponentA {...props} />
} else {
return <ComponentB {...props} />
}
}
The recommended approach. This approach uses the union type and type guards from TypeScript.
type ComponentAType = {
item1: string;
item2: number;
};
type ComponentBType = {
item2: number;
};
// using union type
type GeneralType = ComponentAType | ComponentBType;
// using type guards
const isComponentA = (props: GeneralType): props is ComponentAType => {
// check if the specified property is in the given object
return "item1" in props;
};
const GeneralComponent = (props: GeneralType) => {
if (isComponentA(props)) {
return <ComponentA {...props} />;
} else {
return <ComponentB {...props} />;
}
};
The union type defined using the vertical bar(|
). We are letting TypeScript knows that GeneralComponent
can be of type ComponentAType
or ComponentBType
.
type GeneralType = ComponentAType | ComponentBType;
Now, we can properly defined the types for ComponentAType
and ComponentBType
.
type ComponentAType = {
item1: string;
item2: number;
};
type ComponentBType = {
item2: number;
};
Moving on to type guards. 💂♀
const isComponentA = (props: GeneralType): props is ComponentAType => {
// check if the specified property is in the given object
return "item1" in props;
};
The return type of this function specifies that props is of type ComponentAType
if item1 exists in the given props using the in
operator. Other handy operator such as typeof and instanceof are often use when writing a type guards function.
Lastly, GeneralComponent
could be used as follows.
// ComponentA will be rendered
const Dummy1 = () => <GeneralComponent item1={"asdf"} item2={2} />;
// ComponentB will be rendered
const Dummy2 = () => <GeneralComponent item2={2} />;
Hope that you find it useful and would adapt it to your codebase. Thank you for reading~! 😎👋
Clap to support the author, help others find it, and make your opinion count.