Skip to content

Instantly share code, notes, and snippets.

@nicolasmelo1
Last active February 27, 2026 14:58
Show Gist options
  • Select an option

  • Save nicolasmelo1/e77b1a57267840570be721c504fd1225 to your computer and use it in GitHub Desktop.

Select an option

Save nicolasmelo1/e77b1a57267840570be721c504fd1225 to your computer and use it in GitHub Desktop.
Marking all nullable through extends or through recreating the object
import { z } from "zod";
const originalSchema = z
.object({
age: z.number(),
name: z.string()
})
// Strict defined on the original object schema
.strict();
// ------ Change requested using extends ------
function makeAllNullable<TSchema extends z.AnyZodObject>(schema: TSchema) {
const nullableShape = Object.fromEntries(
Object.entries(schema.shape).map(([key, field]) => [
key,
(field as TSchema["shape"][typeof key]).nullable()
])
) as { [K in keyof TSchema["shape"]]: z.ZodNullable<TSchema["shape"][K]> };
return schema.extend(nullableShape);
}
const nullableSchema = makeAllNullable(originalSchema);
const strictCheck = nullableSchema.safeParse({
age: null,
name: null,
extra: 123 // should be rejected if strict is preserved
});
const nonStrictCheck = nullableSchema.safeParse({
age: null,
name: null
});
console.log("Extended schema", strictCheck.data, strictCheck.success === false ? "✅" : "❌");
console.log(
"Extended schema",
nonStrictCheck.data,
nonStrictCheck.success === true ? "✅" : "❌"
);
console.log("------------------------------------");
// ------ Original implementation ------
function makeAllNullable2<TSchema extends z.AnyZodObject>(schema: TSchema) {
const entries = Object.entries(schema.shape) as [keyof TSchema["shape"], z.ZodTypeAny][];
const newProps = entries.reduce(
(acc, [key, value]) => {
// Apply .nullable() to each field
acc[key] = value.nullable();
return acc;
},
{} as {
[key in keyof TSchema["shape"]]: z.ZodNullable<TSchema["shape"][key]>;
}
);
return z.object(newProps) as z.ZodObject<{
[key in keyof TSchema["shape"]]: z.ZodNullable<TSchema["shape"][key]>;
}>;
}
const nullableSchema2 = makeAllNullable2(originalSchema);
const strictCheck2 = nullableSchema2.safeParse({
age: null,
name: null,
extra: 123 // should be rejected if strict is preserved
});
const nonStrictCheck2 = nullableSchema2.safeParse({
age: null,
name: null
});
console.log("Non-Extended schema", strictCheck2.data, strictCheck2.success === false ? "✅" : "❌");
console.log(
"Non-Extended schema",
nonStrictCheck2.data,
nonStrictCheck2.success === true ? "✅" : "❌"
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment