Create Circular References

How do I make a validator schema reference itself?

In TypeScript, you can trivially create a recursive data type like this:

interface LinkedListNode {
    value: unknown
    next: LinkedListNode | null
}

Because Moat Maker's schemas are stored in JavaScript variables, it isn't as easy to replicate this same recursive-definition behavior.

const linkedListNodeValidator = validator`{
  value: unknown
  // Error: Cannot access 'linkedListNodeValidator' before initialization
  next: ${linkedListNodeValidator} | null
}`;

To accommodate this, Moat Maker provides a .lazy() mechanism, which allows you to register a callback that will fetch a validator instance from somewhere, but only at the moment it's needed. We can fix the above example by using .lazy() like this:

const linkedListNodeValidator = validator`{
  value: unknown
  next: ${validator.lazy(() => linkedListNodeValidator)} | null
}`;

// Example valid data
linkedListNodeValidator.assertMatches({
  value: 1,
  next: {
    value: 2,
    next: null,
  },
});

We were able to have linkedListNodeValidator recursively reference itself, because the self-reference was inside a callback, thus giving time for the linkedListNodeValidator variable to initialize before we tried to reference it.

.lazy() can also be used for other purposes, such as helping later steps access information from earlier steps when following the multi-step validation pattern.

Last updated