title: Typescript require the property if other is defined (requiredIf)
body: <p>Is it possible to define <code>interface</code> or a <code>type</code> in TS which will make sure that if prop <code>A</code> is defined prop <code>B</code> must be also (and if <code>A</code> is not defined/set, <code>B</code> mustn't be either). For example I have smth. like:</p>
  
  <pre><code>export interface IExample {
    a: string;
    b: () =&gt; void;
    c: boolean;
  }
  </code></pre>
  
  <p>Then if I have some object which implements <code>IExample</code> I would like for TS to allow me either having just prop <code>c</code> or both <code>a</code>, <code>b</code> and <code>c</code> and throw compilation error if I have just <code>a</code> and <code>c</code> or <code>b</code> and <code>c</code>.</p>
  
  <p>Better example is using this in React component like in <a href="https://stackoverflow.com/questions/42299335/react-props-set-isrequired-on-a-prop-if-another-prop-is-null-empty">this SO question</a> or even better I want to achieve same functionality like in: <a href="https://github.com/jamiebuilds/react-required-if" rel="nofollow noreferrer">this ReactPropType library</a>.</p>
  
  <p>I have tried to do this via discriminating unions, but I cannot get it to work and it gets too complex when I have couple of props like these (ie <code>requriedIf</code>), but maybe I am just doing it all wrong. Here is example of my code:</p>
  
  <pre><code>export interface INetworkRequestStatusMessageDefaultProps {
    testID?: string;
    networkRequestStatus: NetworkRequestStatus;
  }
  export interface INetworkRequestStatusMessageLoadingProps {
    loadingMessageTranslationKey: string;
    firstTimeUserMessageTranslationKey: string;
    firstTimeUserCallOnActionTranslationKey: string;
    onPressFirstTimeUser: () =&gt; void;
    dataLoaded: boolean;
    errorMessageTranslationKey: never;
    errorCallOnActionTranslationKey: never;
    networkErrorMessageTranslationKey: never;
    onPressError: () =&gt; never;
    deviceConnectedToNetwork: never;
  }
  export interface INetworkRequestStatusMessageFisrtTimeUserProps {
    firstTimeUserMessageTranslationKey: string;
    firstTimeUserCallOnActionTranslationKey: string;
    onPressFirstTimeUser: () =&gt; void;
    dataLoaded: boolean;
    loadingMessageTranslationKey: never;  
    errorMessageTranslationKey: never;
    errorCallOnActionTranslationKey: never;
    networkErrorMessageTranslationKey: never;
    onPressError: () =&gt; never;
    deviceConnectedToNetwork: never;
  }
  export interface INetworkRequestStatusMessageErrorProps {
    errorMessageTranslationKey: string;
    errorCallOnActionTranslationKey: string;
    networkErrorMessageTranslationKey: string;
    onPressError: () =&gt; void;
    deviceConnectedToNetwork: boolean;
    firstTimeUserMessageTranslationKey: undefined;
    firstTimeUserCallOnActionTranslationKey: never;
    onPressFirstTimeUser: () =&gt; never;
    dataLoaded: never;
    loadingMessageTranslationKey: never;
  }
  
  export type NetworkRequestStatusMessageProps =
    | (INetworkRequestStatusMessageDefaultProps &amp;
        (
          | INetworkRequestStatusMessageLoadingProps
          | INetworkRequestStatusMessageFisrtTimeUserProps
          | INetworkRequestStatusMessageErrorProps))
    | (INetworkRequestStatusMessageDefaultProps &amp;
        INetworkRequestStatusMessageErrorProps &amp;
        INetworkRequestStatusMessageFisrtTimeUserProps &amp;
        INetworkRequestStatusMessageLoadingProps);
  </code></pre>
  
  <p>And here is how I am using it:</p>
  
  <pre><code> &lt;NetworkRequestStatusMessage
              networkRequestStatus={this.props.networkRequestStatus}
              deviceConnectedToNetwork={this.props.deviceConnectedToNetwork}
              dataLoaded={this.props.savedWorkoutsLoaded}
              errorCallOnActionTranslationKey={"savedWorkouts.retry"}
              errorMessageTranslationKey={"savedWorkouts.error"}
              firstTimeUserCallOnActionTranslationKey={"savedWorkouts.callOnActionGoToCW"}
              firstTimeUserMessageTranslationKey={"savedWorkouts.firstTimeUser"}
              loadingMessageTranslationKey={"savedWorkouts.loading"}
              networkErrorMessageTranslationKey={"savedWorkouts.networkError"}
              onPressError={this.props.load}
              onPressFirstTimeUser={() =&gt; {
                tron.log("Clicked on go to CW");
              }}
              testID={"SAVED_WORKOUTS"}
            /&gt;
  </code></pre>
  
  <p>But TS is yelling at me saying that: </p>
  
  <pre><code>types of property 'firstTimeUserMessageTranslationKey' are incompatible.
          Type 'string' is not assignable to type 'undefined'
  </code></pre>
  
  <p>And the whole idea behind my code was to make sure that if developer using <code>NetworkRequestStatusMessage</code> must specify either all props or for example all of these props (or none of them): <code>errorMessageTranslationKey</code>, <code>errorCallOnActionTranslationKey</code>, <code>networkErrorMessageTranslationKey</code>, <code>onPressError</code> and similarly for <code>INetworkRequestStatusMessageFisrtTimeUserProps</code></p>