typescriptvalidationschemabunelysiajs

Issues with Defining a Recursive Schema in Elysia


I'm currently working on a project using Elysia, and I'm trying to define a recursive schema for product variants. My goal is to allow each variant to have children, which can also be variants themselves.

Here’s a simplified version of my schema:

import { t } from "elysia";

export const variantSchema = t.Recursive(() =>
  t.Object({
    _id: t.Optional(t.String()),
    ref: t.String(),
    name: t.String({
      minLength: 1,
      error: "Name must be at least 1 character long",
    }),
    additionalPrice: t.Number({
      minimum: 0,
      error: "Additional price must be at least 0",
    }),
    discountPrice: t.Optional(
      t.Number({
        minimum: 0,
        error: "Discount price must be at least 0",
      }),
    ),
    currentStock: t.Number({
      minimum: 0,
      error: "Current stock must be at least 0",
    }),
    children: t.Optional(t.Array(variantSchema)), // Recursive reference
  }),
);

export const saveVariants = t.Object({
  productId: t.String(),
  variants: t.Array(variantSchema),
});

I ensured that I'm using t.Recursive() to define the recursive schema. I checked the property definitions to confirm they are correctly referencing the recursive schema. I followed the documentation regarding recursive types in TypeBox, but I still face issues. Question Has anyone faced a similar issue when defining recursive schemas in Elysia? What could be causing the ReferenceError: Cannot access 'variantSchema' before initialization. And how can I properly define a recursive schema without running into initialization errors?


Solution

  • Well the problem is that you are trying to use variantSchemas value in it's own definition before it is known therefore the error. The documentation of typebox gives a clear example on how to use t.Recursive. In general you want to make use of the parameter that the callback of t.Recursive receives. Applied to your case:

    const variantSchema = t.Recursive(This => t.Object({
      children: t.Optional(t.Array(This))
    }));
    

    should do the trick. The parameter in the example called This refers to the schema that you are currently defining.