Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an optional property with a default value in Zod

Tags:

zod

typescript

I'm using Zod and I want to define one schema for user input that has an optional field with a default value. However, it is being impossible for me to make the runtime behaviour match the inferred type. What I want, is the field to be optional, and when not provided, or provided as undefined, use the default value. If I want this behaviour I can't have the field optional in the generated type, and if I manage to make it optional in the generated type, then it will not get a default value during runtime.

Let me explain it with code:

import { Timestamp } from 'firebase/firestore';
import { z } from 'zod';

export const someSchema = z.object({
  id: z.string(),
  timestamp: z.instanceof(Timestamp),
  type: z.enum(['fever', 'constipation']),
  notes: z.string().optional().default(''),
});

export const someInput = someSchema
  .omit({ id: true })
  .merge(
    z.object({
      timestamp: z
        .date()
        .optional()
        .default(() => new Date()),
    }),
  )
  .partial({
    notes: true,
  });

export const schemaArray = z.array(someSchema);

export type Schema = z.infer<typeof someSchema>;
export type SchemaInput = z.infer<typeof someInput>; // <- Here I expect timestamp to be optional, but it is required


function a({ type, timestamp, notes}: SchemaInput){
  someInput.parse({
  type, timestamp, notes
  })
}

a({type: 'fever'}) <- Error, timestamp is required

like image 314
Danielo515 Avatar asked Jan 26 '26 16:01

Danielo515


1 Answers

As I was pointed out on github schemas usually have an input and an output type. By default, what z.infer does is returning the output type, which is probably the most common usage scenario. Thankfully there is also a method to extract the expected input for the parser, and that is exactly what I needed:

export type SchemaInput = z.input<typeof someInput>;

function a({ type, timestamp, notes}: SchemaInput){
  someInput.parse({
  type, timestamp, notes
  })

Now the inferred schema looks like this:

type SchemaInput = {
    timestamp?: Date | undefined;
    notes?: string | undefined;
    type: "fever" | "constipation";
}

Which is exactly what I needed for a function that takes this input and uses the validator to ensure it has the proper format.

like image 88
Danielo515 Avatar answered Jan 29 '26 10:01

Danielo515



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!