5

I'd like to achieve the following:

export const MediaResponseSchema = z.object({
    mediaId: z.number(),
    childMedias: z.array(z.object(MediaResponseSchema)),
});

I.e. the childMedia should be parsed as an array of the schema I'm declaring.

Max
  • 488
  • 8
  • 19
  • 2
    https://zod.dev/?id=recursive-types – Konrad Sep 23 '22 at 12:14
  • What's the difference between that and copy-pasting the whole zod object? In my real example there's 96 lines of code for the original zod object, so not so neat to copy paste everything again. – Max Sep 23 '22 at 12:55
  • It might be worth asking/answering in a different question if you are concerned about being forced to write out the full interface definition for your type because you can't rely on `z.infer`. That is probably a different issue than just looking for recursion. – Souperman Sep 24 '22 at 03:36

1 Answers1

8

I think the comment mentioning recursive types is correct, but to fully illustrate what is intended, you can use z.lazy, and then reference the schema from within its definition. Your example would become:

import { z } from "zod";

// Zod won't be able to infer the type because it is recursive.
// if you want to infer as much as possible you could consider using a
// base schema with the non-recursive fields and then a schema just for
// the recursive parts of your schema and use `z.union` to join then together.
interface IMediaResponse {
  mediaId: number;
  childMedias: IMediaResponse[];
}

const MediaResponseSchema: z.ZodType<IMediaResponse> = z.lazy(() =>
  z.object({
    mediaId: z.number(),
    childMedias: z.array(MediaResponseSchema)
  })
);

See the Zod Docs on GitHub although I think this should be equivalent to what was linked.

Just to respond to this comment:

What's the difference between that and copy-pasting the whole zod object?

One key difference is that this will recurse indefinitely. The childMedia can be arbitrarily nested with their own child media. If you just copy and pasted then you end up with only one additional level of recursion and you are left with the same problem you started with when you try to decide what to put into the childMedias that you pasted.

Souperman
  • 5,057
  • 1
  • 14
  • 39
  • 2
    Thanks for the thorough answer. A bummer though that Zod/TS can't infer, as my schema contains like hundred rows, and is 5 levels deep, so it's quite cumbersome to duplicate the schema code into interfaces. – Max Sep 26 '22 at 06:39