Capítulo 25 de 61
.refine() attaches a custom validation function to a schema for logic Zod has no built-in check for; it never changes the inferred type, only adds a pass/fail (and optional message) on top.
.refine(fn) / z.refine(fn) (Mini, inside .check()): fn receives the parsed value and must return a truthy/falsy result — never throw, since thrown errors aren't caught by Zod.error option: a static string, or a function receiving the issue ((iss) => ...) for a dynamic message that can reference the failing input.abort option: by default a failing refinement is continuable — Zod keeps running subsequent checks and collects all issues. Setting abort: true makes that refinement short-circuit validation on failure.path option: overrides where the resulting issue is attached in the error tree — typically used on object-level refinements to point the error at a specific field (e.g. a "confirm password" field) rather than the whole object.const myString = z.string().refine((val) => val.length <= 255);
const myString2 = z.string().refine((val) => val.length > 8, {
error: (iss) => `Too short: "${iss.input}"`,
});
// path: attach a cross-field error to a specific key
const passwordForm = z
.object({ password: z.string(), confirm: z.string() })
.refine((data) => data.password === data.confirm, {
error: "Passwords don't match",
path: ["confirm"],
});
// abort: stop at the first failing refinement instead of collecting all issues
const strict = z.string()
.refine((val) => val.length > 8, { error: "Too short!", abort: true })
.refine((val) => val === val.toLowerCase(), { error: "Must be lowercase", abort: true });
path, and controlling continue-vs-abort behavior across chained refinements.false/falsy instead, always.path on an object-level refinement: without it, the error attaches to the whole object rather than the specific field the user should fix (e.g. a mismatched "confirm" field).abort: true only when a later check genuinely doesn't make sense after an earlier one fails.path is the mechanism for pointing a cross-field validation error at the specific field that should show it in a form..extend() throws on refined schemas; .safeExtend() preserves refinements when extending.