Have you ever written a component that has two distinct props interfaces that can be passed in?
type AspectRatioProps = {
aspectRatio: string;
width: number;
}
type WidthHeightProps = {
width: number;
height: number;
}
type Props = {
width?: number;
height?: number;
aspectRatio?: string;
}
export function Image(props: Props) {
// Imagine there is some logic to handle these props
return <div>placeholder</div>
}
The idea here is that you want the consumer of this component to either pass in aspectRatio or width & height, but not both.
Using one Props
interface, you can't communicate that you want one or the other. We know the two distinct interfaces are not a union, but you may think you can intersection the types together. I'm afraid it doesn't turn out so pretty:
export function Image(props: AspectRatioProps | WidthHeightProps) {
// Imagine there is some logic to handle these props
return <div>placeholder</div>
}
We want to be able to pass in an aspectRatio
and width
to this component, or width
and height
, but not both! TypeScript seems to be not cooperating.
I wouldn't be writing this article just to tell you it's not possible though!
We can accomplish our goal with TypeScript function overloads.
export function Image(props: AspectRatioProps): React.ReactElement;
export function Image(props: WidthHeightProps): React.ReactElement;
export function Image(props: AspectRatioProps | WidthHeightProps) {
// Imagine there is some logic to handle these props
return <div>placeholder</div>
}
Function overloads tell your code that there are different signatures for this function. In this case, the function always returns a React element but you could even make it return different types if you wanted!
Check out how TypeScript correctly validates the usage of the component in the sample code in a TypeScript Playground.
Cheers!
Top comments (0)