mcpField
Z
zod-validation-utilities

zod-validation-utilities

github.com/giuseppe-trisciuoglio开发3653.8k 次安装7 周前更新
代码仓库

关于 zod-validation-utilities

面向 TypeScript 开发者的 Zod v4 验证模式技能,指导构建可复用、类型安全的 schema。涵盖错误处理、输入转换及 React Hook Form 集成。

主要功能

  1. 01Zod v4 schema 定义
  2. 02输入强制转换与转换
  3. 03refine 跨字段校验
  4. 04safeParse 错误处理
  5. 05React Hook Form 集成
  6. 06推断输入与输出类型

适用场景

  1. 01验证 API 请求与响应
  2. 02解析表单及环境变量
  3. 03复用团队验证 schema
  4. 04在 React Hook Form 中校验表单

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill zod-validation-utilities

安装后在 Claude Code 中输入/zod-validation-utilities确认已加载。

附带文件references/advanced-patterns.md

详细介绍

Zod 验证实用工具

概述

生产就绪的 Zod v4 模式,可用最少的样板代码实现可复用且类型安全的验证。重点介绍现代 API、可预测的错误处理和表单集成。

适用场景

  • 在 TypeScript 服务中定义请求/响应验证模式
  • 解析来自 API、表单、环境变量或外部系统的不可信输入
  • 统一强制转换、转换和跨字段验证
  • 在团队之间构建可复用的模式实用工具
  • 使用 zodResolver 将 React Hook Form 与 Zod 集成

使用说明

  1. 从严格的对象模式和明确的字段约束开始
  2. 优先使用现代 Zod v4 API 和 error 选项设置错误消息
  3. 在边界处使用强制转换(z.coerce.*),处理类型不确定的输入
  4. 将业务不变量放在靠近模式定义的 refine/superRefine 中
  5. 同时导出模式和推断类型(z.input/z.output),以保持一致
  6. 复用实用模式(电子邮件、ID、日期、分页),减少重复

验证工作流

将验证集成到 API 处理程序或服务时:

  1. 定义边界处的模式(处理程序、队列、配置加载器)
  2. 使用 safeParse 解析,以妥善处理错误
  3. 检查 result.success,根据成功或失败进行分支处理
  4. 在成功路径中使用 result.data,并享受完整的类型推断
  5. 返回格式化后的错误,或继续处理已验证的数据

完整模式请参见示例 7(safeParse 工作流)。

示例

1) 现代 Zod 4 原始类型与对象错误
import { z } from "zod";

export const UserIdSchema = z.uuid({ error: "Invalid user id" });
export const EmailSchema = z.email({ error: "Invalid email" });
export const WebsiteSchema = z.url({ error: "Invalid URL" });

export const UserProfileSchema = z.object(
  {
    id: UserIdSchema,
    email: EmailSchema,
    website: WebsiteSchema.optional(),
  },
  { error: "Invalid user profile payload" }
);
2) 强制转换、预处理与转换
import { z } from "zod";

export const PaginationQuerySchema = z.object({
  page: z.coerce.number().int().min(1).default(1),
  pageSize: z.coerce.number().int().min(1).max(100).default(20),
  includeArchived: z.coerce.boolean().default(false),
});

export const DateFromUnknownSchema = z.preprocess(
  (value) => (typeof value === "string" || value instanceof Date ? value : undefined),
  z.coerce.date({ error: "Invalid date" })
);

export const NormalizedEmailSchema = z
  .string()
  .trim()
  .toLowerCase()
  .email({ error: "Invalid email" })
  .transform((value) => value as Lowercase<string>);
3) 复杂模式结构
import { z } from "zod";

const TagSchema = z.string().trim().min(1).max(40);

export const ProductSchema = z.object({
  sku: z.string().min(3).max(24),
  tags: z.array(TagSchema).max(15),
  attributes: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])),
  dimensions: z.tuple([z.number().positive(), z.number().positive(), z.number().positive()]),
});

export const PaymentMethodSchema = z.discriminatedUnion("type", [
  z.object({ type: z.literal("card"), last4: z.string().regex(/^\d{4}$/) }),
  z.object({ type: z.literal("paypal"), email: z.email() }),
  z.object({ type: z.literal("wire"), iban: z.string().min(10) }),
]);
4) refine 与 superRefine
import { z } from "zod";

export const PasswordSchema = z
  .string()
  .min(12)
  .refine((v) => /[A-Z]/.test(v), { error: "Must include an uppercase letter" })
  .refine((v) => /\d/.test(v), { error: "Must include a number" });

export const RegisterSchema = z
  .object({
    email: z.email(),
    password: PasswordSchema,
    confirmPassword: z.string(),
  })
  .superRefine((data, ctx) => {
    if (data.password !== data.confirmPassword) {
      ctx.addIssue({
        code: "custom",
        path: ["confirmPassword"],
        message: "Passwords do not match",
      });
    }
  });
5) 可选、可空、空值可选与默认值
import { z } from "zod";

export const UserPreferencesSchema = z.object({
  nickname: z.string().min(2).optional(),      // undefined allowed
  bio: z.string().max(280).nullable(),         // null allowed
  avatarUrl: z.url().nullish(),                // null or undefined allowed
  locale: z.string().default("en"),           // fallback when missing
});
6) React Hook Form 集成(zodResolver)
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const ProfileFormSchema = z.object({
  name: z.string().min(2, { error: "Name too short" }),
  email: z.email({ error: "Invalid email" }),
  age: z.coerce.number().int().min(18),
});

type ProfileFormInput = z.input<typeof ProfileFormSchema>;
type ProfileFormOutput = z.output<typeof ProfileFormSchema>;

const form = useForm<ProfileFormInput, unknown, ProfileFormOutput>({
  resolver: zodResolver(ProfileFormSchema),
  criteriaMode: "all",
});
7) 使用 safeParse 的错误处理工作流
import { z } from "zod";
import type { ZodError } from "zod";

const ResultSchema = z.object({ id: z.string(), name: z.string() });

function parseAndHandle(input: unknown) {
  const result = ResultSchema.safeParse(input);

  if (!result.success) {
    const error = result.error as ZodError;
    console.error("Validation failed:", error.errors);
    return { success: false as const, error: error.format() };
  }

  return { success: true as const, data: result.data };
}

提示:有关高级判别联合模式和复杂的 React Hook Form 工作流,请参见 references/advanced-patterns.md。

最佳实践

  • 将模式放在靠近边界的位置(HTTP 处理程序、队列、配置加载器)
  • 可恢复的流程优先使用 safeParse;需要快速失败时使用 parse
  • 共享小型模式实用工具(id、email、slug),以确保一致性
  • 转换/强制转换会改变运行时结构时,使用 z.input 和 z.output
  • 避免过度使用 preprocess;尽可能优先使用明确的 z.coerce.*
  • 将外部载荷视为不可信数据,并始终在使用前进行验证

限制与警告

  • 确保示例与已安装的 zod 主版本匹配(此处展示 v4 API)
  • 在 Zod v4 模式中,error 是自定义错误的首选选项
  • 判别联合要求各变体使用稳定的判别键
  • 强制转换可能会掩盖上游的错误数据;请添加边界限制和细化验证,做好防护

评论

支持 Markdown