Format Zod Errors Into Field Messages

Convert a Zod validation error into a keyed field-message map so a form can render every issue next to the input that caused it.

TypescriptForm Validation

Code

snippet
import { z } from "zod";

export interface FieldErrors {
  [field: string]: string[];
}

export function formatIssues(error: z.ZodError): FieldErrors {
  const result: FieldErrors = {};
  for (const issue of error.issues) {
    const field = issue.path.length > 0 ? issue.path.join(".") : "_root";
    (result[field] ??= []).push(issue.message);
  }
  return result;
}

export function validate<T extends z.ZodTypeAny>(schema: T, input: unknown) {
  const parsed = schema.safeParse(input);
  if (parsed.success) {
    return { ok: true as const, data: parsed.data };
  }
  return { ok: false as const, errors: formatIssues(parsed.error) };
}