Search code examples
typescriptaurelia

Property 'on' does not exist on type 'FluentRules<any, any> | FluentEnsure<any> | FluentRuleCustomizer<any, any>'.


I am writing aurelia-validation and having issue using on which is part of different overload (FluentRuleCustomizer) class. When I use ruleBuilder['on'](field); it works fine, but when I change that to ruleBuilder.on(field); I get a red squiggly line on ruleBuilder.on(field);. See the below code and screenshot.

import { ValidationRules, FluentRuleCustomizer, FluentEnsure, FluentRules } from 'aurelia-validation';
import { on } from 'cluster';
export class FormHelper {
  private static initializedForms = [];

  public static initializeFormRules(form) {
    if (this.initializedForms.indexOf(form) > -1) {
      return;
    }
    this.initializedForms.push(form);
    for (const field of form.fields) {
      if (field.validation.isValidate) {
        let ruleBuilder: | FluentRules<any, any> | FluentEnsure<any> | FluentRuleCustomizer<any, any>;
        ruleBuilder = ValidationRules
          .ensure("value")
          .displayName(field.label);

        const rules = Object.keys(field.validation.validationRule)
          .map(key => ({ key, value: field.validation.validationRule[key] }));

        for (const rule of rules) {
          ruleBuilder = ruleBuilder[rule.key](rule.value);
        }
//         ruleBuilder['on'](field);
        ruleBuilder.on(field);
      }
    }
  }
} 

Link to all exported classes exposed for aurelia-validation

Any help is really appreciated :)

enter image description here


Solution

  • The typings / api of aurelia-validation aren't ideal for dynamically building up rules like this, so you need to cheat a little.

    Just change your initial declaration to this:

    let ruleBuilder: FluentRuleCustomizer<any, any> = ValidationRules
          .ensure("value")
          .displayName(field.label) as any;
    

    It will not actually be a FluentRuleCustomizer there (hence the as any is needed), but it will be after your logic below has applied any rules to it. Tbh I think .displayName() should just return a FluentEnsure or FluentRuleCustomizer (both have the .on() method that does the same thing) but that's another discussion.

    You probably want to double check that any rules were actually applied, or the .on() will error out:

    if (rules.length) {
        ruleBuilder.on(field);
    }