reactjstypescript

How to make prop mandatory based on another prop being passed


I have some code for a form:

interface FormProps {
  regexPreset?: RegexPresets;
  customRegex?: RegExp;
  description?: string;
  inputTitle: string;
  errorMessage?: string;
}
const Form: React.FC<FormProps> = props => {
  return <div> somestuff </div>
} 

If I pass in a customRegex, I want the compiler to throw an error if errorMessage is not passed (make errorMessage a mandatory property).

The closest thing that I've come to is this StackOverflow post, but I'm unsure whether I can apply this to my use case.

Any pointers would be gladly received.


Solution

  • To simplify lets say we have following props

    interface FormProps {
      inputTitle: string;
      description?: string;
      
      customRegex?: string;
      errorMessage: string;
    }
    

    Here 'inputTitle' prop is mandatory, description is optional but errorMessage prop has to be there (mandatory) only when customRegex (optional) prop is present.

    Create a type for non-conditional props

    interface FormMainProps {
      description?: string;
      inputTitle: string;
    }
    

    Now create a type for conditional props only when conditional prop 'customRegex' is present

    interface FormErrorProps {
      customRegex: string; 
      errorMessage: string;
    }
    

    Now create an additional type when conditional prop is not present (to give idea for possible values present in object)

    interface FormNotErrorProps {
      customRegex?: undefined; 
      errorMessage?: never; 
      // important step; so if customRegex prop is not present errorMessage should not be there and vice-versa
    }
     
    

    Now your FormProps will be

    type FormProps =  FormMainProps & (FormErrorProps | FormNotErrorProps);
    

    Following scenarios will give error as needed:

    let a: FormProps;
    
    a = {
      inputTitle: "Title",
      customRegex: "asdasd"
    };
    
    /*
    Type '{ inputTitle: string; customRegex: string; }' is not assignable to type 'FormProps'.
    Type '{ inputTitle: string; customRegex: string; }' is not assignable to type 'FormMainProps & FormErrorProps'.
        Property 'errorMessage' is missing in type '{ inputTitle: string; customRegex: string; }' but required in type 'FormErrorProps'.ts(2322)
    */
    
    
    a = {
      inputTitle: "Title",
      errorMessage: "asdasd"
    };
    
    /*
    Type '{ inputTitle: string; errorMessage: string; }' is not assignable to type 'FormProps'.
    Type '{ inputTitle: string; errorMessage: string; }' is not assignable to type 'FormMainProps & FormNotErrorProps'.
        Property 'customRegex' is missing in type '{ inputTitle: string; errorMessage: string; }' but required in type 'FormNotErrorProps'.
    */
    

    while below ones are fine:

    a = {
      inputTitle: "Title",
      errorMessage: "asdasd",
      customRegex: "Title",
    };
    
    a = {
      inputTitle: "Title"
    };