DEV Community

Michael Sholty
Michael Sholty

Posted on

Using TypeScript Function Overloads For Distinct Component Props

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>
}
Enter fullscreen mode Exit fullscreen mode

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>
}
Enter fullscreen mode Exit fullscreen mode

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>
}
Enter fullscreen mode Exit fullscreen mode

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)