Search code examples
typescriptvue.jsvuejs3zod

Create recursive zod schema


i am currently working on a zod schema which looks like this:

export const ActionTypeValidator = z.object({
  action: z.any(),
  state: z.any(),
  actionGroups: z.array(ActionGroupTypeValidator).optional(),
})
export type ActionType = z.infer<typeof ActionTypeValidator>

export const ActionGroupTypeValidator = z.object({
  id: z.string(),
  name: z.string(),
  actions: z.array(ActionTypeValidator),
})
export type ActionGroupType = z.infer<typeof ActionGroupTypeValidator>

I get the following two errors:

  1. Vue: ActionTypeValidator implicitly has type any because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
  2. Vue: ActionGroupTypeValidator implicitly has type any because it does not have a type annotation and is referenced directly or indirectly in its own initializer.

I already tried a lot with z.lazy but i can't get this stuff to work. Anyone knows how to solve this issue?


Solution

  • I got a working solution now.

    const InternalActionTypeValidator = z.object({
      action: z.any(),
      state: z.any(),
    })
    type InternalActionType = z.infer<typeof InternalActionTypeValidator> & {
      actionGroups?: z.infer<typeof ActionGroupTypeValidator>
    }
    
    export const ActionTypeValidator = InternalActionTypeValidator.extend({
      // eslint-disable-next-line @typescript-eslint/no-use-before-define
      actionGroups: z.lazy(() => ActionGroupTypeValidator).optional(),
    })
    export type ActionType = z.infer<typeof ActionTypeValidator>
    
    export const ActionGroupTypeValidator = z.object({
      id: z.string(),
      name: z.string(),
      actions: z.array(ActionTypeValidator),
    })
    export type ActionGroupType = z.infer<typeof ActionGroupTypeValidator>
    

    The secret was the combination of z.lazy and extending the InternalActionType with

    & {
          actionGroups?: z.infer<typeof ActionGroupTypeValidator>
        }