Search code examples
node.jstypescriptfunctionoverloading

Use overloaded function with default initializer


Hi I'm trying to overload a function that change return type on parameter

isValidPropertyValue(propertyName: string, value: any,
    options?: { errors: true }): ValidationWithErrors;
  isValidPropertyValue(propertyName: string, value: any,
    options?: { errors: false }): boolean
  isValidPropertyValue(propertyName: string, value: any,
    options = { errors: false }): boolean | ValidationWithErrors {
    if (typeOf(propertyName) !== "string") throw new Error("propertyName must be a string");

    const conditions = this.properties[propertyName];
    if (!conditions) {
      return options.errors ? {
        valid: false,
        errors: [{
          property: propertyName,
          error: `Unauthorized property '${propertyName}'`
        }]
      } : false;
    }

    const errors: PropertyError[] = [];
    for (const [condition, validator] of Object.entries(propertyValidators)) {
      if (conditions[condition]) {
        try {
          validator(conditions[condition], value);
        } catch (e: any) {
          errors.push({ property: propertyName, error: e.message });
        }
      }
    }

    return options.errors ? { valid: !errors.length, errors } : !errors.length;
  }

I have set a default initializer on the option parameter like you can see but when I'm trying to call the function I got an error

TS2554: Expected 3 arguments, but got 2. 

Futhermore it doesn't change my return type and keep it on ValidationWithError even if I set the option to false


Solution

  • I'm not sure how you go the argument error. TS2554: Expected 3 arguments, but got 2. I wasn't able to reproduce that with your code. But if you remove the ? from the first signature, TS will correctly infer the return type. It makes sense because when options is undefined or { errors: false }, you want to return a boolean but you only return ValidationErrors when it's { errors: true } and not when it's undefined.

    interface ValidationWithErrors {
      valid: boolean;
      errors: { property: string; error: string }[];
    }
    
    function isValidPropertyValue(
      propertyName: string,
      value: any,
      options: { errors: true }
    ): ValidationWithErrors;
    function isValidPropertyValue(
      propertyName: string,
      value: any,
      options?: { errors: false }
    ): boolean;
    function isValidPropertyValue(
      propertyName: string,
      value: any,
      options = { errors: false }
    ): boolean | ValidationWithErrors {
      if (options.errors) {
        return {
          valid: false,
          errors: [{ property: propertyName, error: 'invalid value' }],
        };
      }
      return false;
    }
    
    const isValid = isValidPropertyValue('property', 'value'); // boolean
    const validationWithErrors = isValidPropertyValue('property', 'value', {
      errors: true,
    }); // ValidationWithErrors