Photo by Vitya Lapatey on Unsplash
Typescript: Create a React Component with conditional props for each variant
Instead of making a prop optional, we can specify different variants for a component and ensure type safety
You have a lovely component that takes some props.
interface PropsA {
pear: string;
apple: string;
}
const ComponentA: FC<PropsA> = (props) => {
return ///;
};
We then realise that we have another component which looks the same but has a different prop that is essential to this second component, and not needed in the first.
interface PropsB {
pear: string;
apple: string;
plum: string; // essential for ComponentB
}
const ComponentB: FC<PropsB> = (props) => {
return /// identical looking component to componentA;
};
Now we have 2 components to maintain, even though they share 2 of the same props, and have all the same styles etc.
You could just make it into one component and make the extra prop conditional plum?:string
and then check for the extra prop in the component:
interface PropsAB {
pear: string;
apple: string;
plum?: string;
}
const Component: FC<PropsAB> = (props) => {
if(props.plum){
///
} else {
///
}
};
This approach is ok most of the time, but another developer might not realise that the plum
is only needed when the component is of type B, (and is essential), and not required when it is of type A.
interface BaseProps {
// shared props
pear: string;
apple: string;
}
export type Variant = 'a' | 'b'; // label our variants
interface AProps extends BaseProps {
// give each variant their own interface which extends the shared props with 'variant' prop
variant: 'a';
}
interface BProps extends BaseProps {
variant: 'b';
plum: string; // our extra prop which is required only for this variant
}
export type ComponentProps = AProps | BProps;
const Component = (props: ComponentProps) => {
return <div {...props}>Fruit</div>;
};
export default Component;
Now we can use our component, specify the variant, and get helpful typescript errors and auto-complete.
const App = () => {
return (
<>
<Component variant="a" pear="" apple="" /> // OK
<Component variant="b" pear="" apple="" /> // Error: Property 'plum' is missing
</>
);
};
export default App;