Skip to content

Instantly share code, notes, and snippets.

@JWPapi
Created July 6, 2025 16:09
Show Gist options
  • Save JWPapi/8c083af942a017780721016cf74f4471 to your computer and use it in GitHub Desktop.
Save JWPapi/8c083af942a017780721016cf74f4471 to your computer and use it in GitHub Desktop.
transform schema to be client conform nextjs
import {
z,
ZodType,
ZodObject,
ZodArray,
ZodOptional,
ZodNullable,
ZodDate,
ZodCustom,
ZodPipe,
ZodTransform
} from 'zod/v4'
import { ObjectId } from 'mongodb'
export type ToClientZodType<T extends ZodType> = T extends ZodDate
? ZodPipe<ZodDate, ZodTransform<string, Date>>
: T extends ZodCustom<ObjectId, ObjectId>
? ZodPipe<ZodCustom<ObjectId, ObjectId>, ZodTransform<string, ObjectId>>
: T extends ZodOptional<infer Inner>
? ZodOptional<ToClientZodType<Inner extends ZodType ? Inner : never>>
: T extends ZodNullable<infer Inner>
? ZodNullable<ToClientZodType<Inner extends ZodType ? Inner : never>>
: T extends ZodArray<infer Element>
? ZodArray<ToClientZodType<Element extends ZodType ? Element : never>>
: T extends ZodObject<infer Shape>
? ZodObject<{ [K in keyof Shape]: Shape[K] extends ZodType ? ToClientZodType<Shape[K]> : Shape[K] }>
: T
export function toClientSchema<T extends ZodType>(schema: T): ToClientZodType<T> {
// Base case: Handle Date transformation
if (schema instanceof ZodDate) {
const zodDate = schema as ZodDate
return zodDate.transform(date => date.toISOString()) as unknown as ToClientZodType<T>
}
// Base case: Handle ObjectId transformation by checking metadata
if (schema instanceof ZodCustom && schema.meta()?.bsonType === 'objectId') {
const zodCustom = schema as ZodCustom<ObjectId, ObjectId>
return zodCustom.transform(id => id.toString()) as unknown as ToClientZodType<T>
}
// --- Recursive cases for unwrapping and re-wrapping schemas ---
if (schema instanceof ZodOptional) {
const zodOptional = schema as unknown as ZodOptional<any>
return toClientSchema(zodOptional.unwrap()).optional() as unknown as ToClientZodType<T>
}
if (schema instanceof ZodNullable) {
const zodNullable = schema as unknown as ZodNullable<T>
return toClientSchema(zodNullable.unwrap()).nullable() as unknown as ToClientZodType<T>
}
if (schema instanceof ZodArray) {
const zodArray = schema as ZodArray<any>
return z.array(toClientSchema(zodArray.element)) as unknown as ToClientZodType<T>
}
if (schema instanceof ZodObject) {
const newShape: { [k: string]: ZodType } = {}
for (const key in schema.shape) {
newShape[key] = toClientSchema(schema.shape[key])
}
return z.object(newShape) as unknown as ToClientZodType<T>
}
// Return the original schema if no transformation is needed
return schema as unknown as ToClientZodType<T>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment