Capítulo 28 de 61
Transforms perform a one-way reshaping of a value (unlike codecs, which are bidirectional) — they accept anything and return a new value, optionally reporting validation issues via a ctx parameter.
z.transform(fn): accepts any input, returns fn(val) as the parsed output; the inferred output type comes from what fn returns..transform(fn): convenience method for the common schema.pipe(z.transform(fn)) pattern (Zod only, no Zod Mini equivalent — use z.pipe() there).ctx.issues / z.NEVER: inside a transform, push a validation issue onto ctx.issues to report failure, then return z.NEVER to exit without corrupting the inferred return type..transform(async (val) => ...) is supported, but parsing must then use .parseAsync()/.safeParseAsync() — using the sync .parse() throws.z.preprocess(fn, schema): the inverse composition — pipe a raw-value transform into a schema. Input type defaults to unknown; annotate the preprocessor's parameter type to narrow z.input<> (useful for libraries like react-hook-form that derive form value types from the input type).const castToString = z.transform((val) => String(val));
castToString.parse(123); // => "123"
const coercedInt = z.transform((val, ctx) => {
const parsed = Number.parseInt(String(val));
if (Number.isNaN(parsed)) {
ctx.issues.push({ code: "custom", message: "Not a number", input: val });
return z.NEVER;
}
return parsed;
});
const stringToLength = z.string().transform(val => val.length);
const idToUser = z.string().transform(async (id) => db.getUserById(id));
const user = await idToUser.parseAsync("abc123");
const trimmed = z.preprocess(
(val: string | null | undefined) => val?.trim() ?? "",
z.string()
);
z.NEVER, async transforms requiring parseAsync, and narrowing a preprocessor's accepted input type.ctx.issues and return z.NEVER instead..parse() (sync) on a schema with an async transform: throws — must use .parseAsync()/.safeParseAsync().ctx.issues.push(...) + return z.NEVER is the correct way to fail validation from inside a transform — never throw..parse() call on that schema to be the async variant.