Skip to content

.custom()

Runs validator(value) on values that passed the type check and passes when it returns true. The function receives the validator’s typed value, an int for l.int(), and is never called for null; add .required() if null must fail. A thrown exception counts as false. On schemas, lists, maps and unions, the function runs only when every child passed, so it receives well-typed data. Custom validators has the longer treatment.

Self custom(CustomValidator<T> validator, {String? message, MessageBuilder? messageBuilder})
typedef CustomValidator<T> = bool Function(T value);
Parameter Type Meaning
validator bool Function(T) Return true to pass. T is the validator’s value type.
message String? Replaces the default error message.
messageBuilder MessageBuilder? Builds the message from the issue. message wins when both are given. See Message builders.

Code custom. Default message: value does not pass custom validation. value is replaced by the field name when there is one. Pass message in practice; the default says nothing about the rule.

@WithCustomValidator(fn, message: ...). fn has to be a top-level function or a static method and takes the field’s type: bool isEven(int value).

bool isEven(int value) => value.isEven;
final evenNumber = l.int().custom(isEven, message: 'must be even');
evenNumber.validate(input)+2-2
  1. valid: 4
  2. invalid: 3must be even
  3. valid: null
  4. invalid: '4'value must be an integer

Without a message, and when the function throws:

[value does not pass custom validation]
[value does not pass custom validation]