Capítulo 16 de 29

Chapter 16: Custom Errors

Core Idea

A validator's return value can be any truthy value, not just a string — numbers, booleans, objects, or arrays all count as "there is an error," with full type inference on whatever shape you choose.

Key Concepts

  • Truthiness rule: any truthy return means "invalid"; false/undefined/null mean "valid" — this is the whole contract, no special "error" wrapper type required.
  • Richer shapes are first-class: an object like { message, severity, code } is just as valid a return as a plain string, and TypeScript infers that exact shape for consumers.
  • This is what makes structured error UIs (severity levels, error codes for i18n lookup, multiple messages per field via an array) possible without a separate error-formatting layer.

Code Examples

<form.Field
  name="email"
  validators={{
    onChange: ({ value }) => {
      if (!value.includes('@')) {
        return { message: 'Invalid email format', severity: 'error', code: 1001 }
      }
      return undefined
    },
  }}
/>
  • What it demonstrates: returning a structured object instead of a bare string — the consuming UI can branch on severity or look up code in a translation table.

Key Takeaways

  1. Don't reach for a separate error-formatting utility to attach severity/codes/i18n keys to validation failures — return that shape directly from the validator.
  2. The truthy/falsy contract means 0 and '' would count as "valid" if accidentally returned from a validator meant to signal an error — be deliberate about always returning a real message/object or undefined, never an ambiguous falsy value from a bug.
  3. TypeScript infers whatever error shape you return, so downstream error-rendering code gets full autocomplete on err.severity/err.code — no manual typing needed.

Connects To

  • Ch008 Form Validation: where these validators are configured.
  • Ch028 Utility & State Types: ValidationError (typed as unknown precisely to allow this flexibility).