Zod and Data modelling

My plan is to develop that app. It has a hierarchic data structure. Zod should validate the data. To model the data in zod we need to create a recursive structure as follows: const baseCategorySchema = z.object({ name: z.string().min(2).max(50), percent: z.number().gte(1), amount: z.number().optional(), percentages: z.array(percentageSchema) }); type CategoryType = z.infer & { categories: CategoryType[]; }; export const categorySchema: z.ZodType = baseCategorySchema.extend({ categories: z.array(z.lazy(() => categorySchema)) }); With z.lazy() I can access the categorySchema even though it's not yet initialised. Now I can do the following: export type CategorySchema = typeof categorySchema; export type CategorySchemaType = z.infer; const testData: CategorySchemaType = { amount: 1000, name: 'root', categories: [ { name: 'risk part', percent: 80, categories: [ { name: 'ETFs', percent: 70, categories: [], percentages: [ { name: 'world', percent: 70 }, { name: 'EM', percent: 30 } ] }, { name: 'sustainable', percent: 20, categories: [], percentages: [{ name: 'ETF sustainable', percent: 100 }] }, { name: 'commondities', percent: 10, categories: [], percentages: [{ name: 'ETF commodities', percent: 100 }] } ], percentages: [] }, { name: 'low risk', percent: 20, categories: [], percentages: [{ name: 'government bond', percent: 100 }] } ] };

Feb 25, 2025 - 21:49
 0
Zod and Data modelling

My plan is to develop that app.

Image description

It has a hierarchic data structure.
Zod should validate the data. To model the data in zod we need to create a recursive structure as follows:

const baseCategorySchema = z.object({
  name: z.string().min(2).max(50),
  percent: z.number().gte(1),
  amount: z.number().optional(),
  percentages: z.array(percentageSchema)
});

type CategoryType = z.infer<typeof baseCategorySchema> & {
  categories: CategoryType[];
};

export const categorySchema: z.ZodType<CategoryType> = baseCategorySchema.extend({
  categories: z.array(z.lazy(() => categorySchema))
});

With z.lazy() I can access the categorySchema even though it's not yet initialised.

Now I can do the following:

export type CategorySchema = typeof categorySchema;

export type CategorySchemaType = z.infer<CategorySchema>;

const testData: CategorySchemaType = {
  amount: 1000,
  name: 'root',
  categories: [
    {
      name: 'risk part',
      percent: 80,
      categories: [
        {
          name: 'ETFs',
          percent: 70,
          categories: [],
          percentages: [
            { name: 'world', percent: 70 },
            { name: 'EM', percent: 30 }
          ]
        },
        {
          name: 'sustainable',
          percent: 20,
          categories: [],
          percentages: [{ name: 'ETF sustainable', percent: 100 }]
        },
        {
          name: 'commondities',
          percent: 10,
          categories: [],
          percentages: [{ name: 'ETF commodities', percent: 100 }]
        }
      ],
      percentages: []
    },
    {
      name: 'low risk',
      percent: 20,
      categories: [],
      percentages: [{ name: 'government bond', percent: 100 }]
    }
  ]
};