Skip to content

Instantly share code, notes, and snippets.

@AndrewIngram
Last active October 8, 2025 20:51
Show Gist options
  • Save AndrewIngram/c732377ced4e41bc4e7ac793defc8494 to your computer and use it in GitHub Desktop.
Save AndrewIngram/c732377ced4e41bc4e7ac793defc8494 to your computer and use it in GitHub Desktop.
Use any standard schema within zod3
import type { StandardSchemaV1 } from '@standard-schema/spec';
import { ZodError, ZodIssueCode, type ZodType, type ZodTypeDef, z } from 'zod/v3';
/**
* Wrap any Standard Schema as a Zod schema.
* Always use `parseAsync` (or `safeParseAsync`) on the returned schema.
*/
export function z3FromStandard<S extends StandardSchemaV1>(
schema: S
): ZodType<StandardSchemaV1.InferOutput<S>> {
const base = z.any().transform(async (value) => {
const res = await Promise.resolve(schema['~standard'].validate(value));
if ('issues' in res) {
// Map Standard Schema issues -> ZodError
throw new ZodError(
res.issues?.map((i) => ({
code: ZodIssueCode.custom,
message: i.message,
path: (i.path ?? []).map((p) =>
typeof p === 'object' && p && 'key' in p ? p.key : p
) as Array<string | number>,
})) ?? []
);
}
return res.value as StandardSchemaV1.InferOutput<S>;
});
// Cast to the cleaner ZodType<Output> surface
return base as unknown as ZodType<StandardSchemaV1.InferOutput<S>>;
}
@AndrewIngram
Copy link
Author

import { z as z4 } from 'zod/v4';

const testz4Schema = z4.object({
  a: z4.string(),
  b: z4.number(),
});

const testz3Schema = z.object({
  a: z.string(),
  b: z3FromStandard(testz4Schema)
});

type Testz3Schema = z.infer<typeof testz3Schema>;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment