How to change all optional fields to nullish given a zod object? #2050
-
I have a Zod object as so: const Person = z.object({
firstName: z.string(),
lastName: z.string(),
email: z.string().optional(),
address: z.string().nullable(),
}) I'd like to have it so that when it parses in a specific function, all function parseFromBackend(zodObject: z.ZodObject) {
// what to do here?
}
parse(Person); |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 4 replies
-
Can you just make all the fields nullish? This allows null or undefined. Seems like it's easier to just do this: const Person = z.object( {
firstName: z.string(),
lastName: z.string(),
email: z.string().nullish(),
address: z.string().nullish(),
} )
console.log(
Person.safeParse( {
firstName: 'John',
lastName: 'Doe',
email: undefined,
address: undefined,
} ).success
) // true
console.log(
Person.safeParse( {
firstName: 'John',
lastName: 'Doe',
email: null,
address: null,
} ).success
) // true If you found my answer satisfactory, please consider supporting me. Even a small amount is greatly appreciated. Thanks friend! 🙏 |
Beta Was this translation helpful? Give feedback.
-
Is this what you are looking for? function makeOptionalPropsNullable<Schema extends z.AnyZodObject> ( schema: Schema ) {
const entries = Object.entries( schema.shape ) as
[ keyof Schema[ 'shape' ], z.ZodTypeAny ][]
const newProps = entries.reduce( ( acc, [ key, value ] ) => {
acc[ key ] = value instanceof z.ZodOptional
? value.unwrap().nullable()
: value
return acc
}, {} as {
[ key in keyof Schema[ 'shape' ] ]: Schema[ 'shape' ][ key ] extends z.ZodOptional<infer T>
? z.ZodNullable<T>
: Schema[ 'shape' ][ key ]
} )
return z.object( newProps )
}
const Person = z.object( {
firstName: z.string(),
lastName: z.string(),
email: z.string().optional(),
address: z.string().nullable(),
} )
const serverPerson = makeOptionalPropsNullable( Person )
type ServerPerson = z.infer<typeof serverPerson>
// type ServerPerson = {
// firstName: string
// lastName: string
// email: string | null
// address: string | null
// }
console.log(
serverPerson.safeParse( {
firstName: 'John',
lastName: 'Doe',
email: null,
address: null,
} ).success
) // true
console.log(
serverPerson.safeParse( {
firstName: 'John',
lastName: 'Doe',
email: undefined,
address: undefined,
} ).success
) // false If you found my answer satisfactory, please consider supporting me. Even a small amount is greatly appreciated. Thanks friend! 🙏 |
Beta Was this translation helpful? Give feedback.
-
I want field non required but if it is not blank, it minimal 3 char I have do this But, if field empty, appear warning "must be at least 3 characters" :( |
Beta Was this translation helpful? Give feedback.
-
Here is a version that works with Zod v4 import { z } from 'zod'
/**
* Recursively converts every `.optional()` in a schema to
* “required + nullable” so that no field can be `undefined`
* (OpenAI‑JSON compliant) but all may be `null`.
*/
export function optionalToNullable<S extends z.ZodTypeAny>(schema: S): S {
// 1 · Optional ─► unwrap ─► make nullable
if (schema instanceof z.ZodOptional) {
return optionalToNullable(
schema.unwrap() as any,
).nullable() as unknown as S
}
// 2 · Object ─► run on every property (keeps passthrough/strict options)
if (schema instanceof z.ZodObject) {
const transformed = Object.fromEntries(
Object.entries(schema.shape).map(([k, v]) => [
k,
optionalToNullable(v),
]),
)
return z.object(transformed) as unknown as S
}
// 3 · Collections / composites
if (schema instanceof z.ZodArray)
return z.array(
optionalToNullable(schema.element as any),
) as unknown as S
if (schema instanceof z.ZodRecord)
return z.record(
z.string(),
optionalToNullable(schema.valueType as any),
) as unknown as S
if (schema instanceof z.ZodTuple)
return z.tuple(
schema.def.items.map((x) => optionalToNullable(x as any)) as any,
) as unknown as S
if (schema instanceof z.ZodUnion)
return z.union(
schema.def.options.map((x) => optionalToNullable(x as any)),
) as unknown as S
if (schema instanceof z.ZodIntersection)
return z.intersection(
optionalToNullable(schema.def.left as any),
optionalToNullable(schema.def.right as any),
) as unknown as S
// 4 · Leaf schema ─► untouched
// 4 · Additional collection types
if (schema instanceof z.ZodMap)
return z.map(
optionalToNullable(schema.def.keyType as any),
optionalToNullable(schema.def.valueType as any),
) as unknown as S
if (schema instanceof z.ZodSet)
return z.set(
optionalToNullable(schema.def.valueType as any),
) as unknown as S
if (schema instanceof z.ZodPromise)
return z.promise(
optionalToNullable(schema.def.type as any),
) as unknown as S
// 5 · Leaf schema ─► untouched
return schema
} |
Beta Was this translation helpful? Give feedback.
Is this what you are looking for?