SJT
SJT

Reputation: 252

Validating conditional pairs of props with Typescript

I'm struggling to understand how to validate that two props either exist or don't.

In other words, they are both optional, but if one exists, the other must also.

I don't quite understand how a conditional type would work in this scenario, in all the examples I've seen the condition is if the class extends another class or not, so how would that work here?

interface DateInputProps {
  onDateChange: (date: Date) => void;
  date: any;
}

interface DateInputPropsNull {}

type SelectiveProps<T> = T extends _what?_
  ? DateInputPropsNull
  : DateInputProps;

class DateInput extends React.Component<
  SelectiveProps<_what?_>,
  DateInputState
> {

    render() {
        const {
          date = this.state.date,
          onDateChange = (date: any) => this.setState({ date })
        } = this.props;
        ...
    }

}

I would then expect to be able to do:

<DateInput /> //No type error
<DateInput date="2011-01-05" onDateChange={(date)=> console.log(date)}/> //No type error
<DateInput date="2011-01-05" /> //Error - onDateChange is required

Upvotes: 3

Views: 1767

Answers (2)

Tien Duong
Tien Duong

Reputation: 2595

You can do something like this

interface DateInputProps {
  onDateChange: (date: Date) => void;
  date: string;
}

interface DateInputPropsNull {
  onDateChange?: undefined,
  date?: undefined
}

type SelectiveProps = DateInputProps | DateInputPropsNull

class DateInput extends React.Component<SelectiveProps>

So if you pass one of the value you will get the type error. The only problem with this solution is that when you pass undefined to date or onDateChange, it will not give you the error.

<DateInput /> //No type error
<DateInput date="2011-01-05" onDateChange={(date)=> console.log(date)}/> //No type error
<DateInput date="2011-01-05" /> //Error - onDateChange is required
<DateInput date={undefined} onDateChange={undefined} /> // No type error

Upvotes: 5

rrd
rrd

Reputation: 5967

I suppose you can do it like this:

interface IDateInputProps {
  date?: any;
  onDateChange()?: void;
}

export class DateInput extends React.Component<IDateInputProps, DateInputState> {
  render() {
    const { date, onDateChange } = this.props;

    if ((!date && onDateChange) || (date && !onDateChange)) {
      throw new Error('"date" and "onDateChange" props must occur together");
    }

    ...
  }
}

I haven't tested it, but I think that would do what you want.

Upvotes: 0

Related Questions