abdeniz
abdeniz

Reputation: 35

Is there a way for two props to be required if one of them is used?

I'm trying to have two props that are passed into the component to be required if one of them is used.

export type ComponentProps = {
  children: ReactNode
  height?: number
  width?: number
}

const Component: React.FC<ComponentProps> = ({
  children,
  height,
  width
}) => {...

So how can I make it so that when height prop is passed, then the Component also requires the width prop to be passed?

I've tried having an optional object type called sizeProps and destructuring the height and width in the Component, the type didn't seem to work. Also tried extending and also tried using the Partial<> utility type, couldn't get it to work. Does 'Discriminating Unions' sound like the correct approach? Couldn't really understand how I should use it for this instance though

Upvotes: 0

Views: 920

Answers (1)

geoM
geoM

Reputation: 497

In general discriminated unions help with that kind of problem.

You need a discriminator, which is a string differentiating (discriminating) the members of the union.

type Naked = {
    type: 'naked';
    children: React.ReactNode;
};

type Sized = {
    type: 'sized';
    height: number;
    width: number;
};

type ComponentProps = Naked | Sized;

export const MyComponent: React.FC<ComponentProps> = props => {
    return props.type === 'sized' ? (
        <span>
            {
                // TS control flow "knows" that we are dealing with the "Sized" type here,
                // In other words: props are narrowed to the Size type
                props.width * 2 + props.height
            }
        </span>
    ) : (
        <span>{props.children}</span>
    );
};

You can read more about that here: https://thoughtbot.com/blog/the-case-for-discriminated-union-types-with-typescript

Not sure if that is the best way to help your case though, maybe take a step back and consider using different components for different things.

Upvotes: 1

Related Questions