Communitygithub.com

axross/skills

一个固执己见的智能体技能库。

skills 是什么?

axross/skills 是一个专为 AI 智能体(如 Claude Code、Cursor、Codex 等)设计的技能库,提供了高度结构化和最佳实践驱动的 Zod Schema 使用指南。它专注于所有与 Zod 相关的操作(编写 schema、解析、解码、错误处理等),通过一系列深入的参考文档(如验证边界、模块设计、性能优化、安全策略等)来确保 schema 层的正确性和高效性。该技能明确区分了 schema 层与其他关注点(如框架、应用安全、状态管理)的边界,并针对 Zod 4 进行了专门优化,同时提供了从 Zod 3 迁移的检测信号。其主要价值在于为开发者提供了一套权威、一致且完整的 Zod 使用规范,避免了常见陷阱,并显著提升了代码质量和运行时性能。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add axross/skills

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Zod Schema

当任何变更涉及 Zod 时,请使用此能力——无论是编写 schema、放置解析调用、解码负载、还是处理错误。它拥有 schema 层:形状、解析调用、形状产生的类型、产生的错误,以及在网络格式和领域模型之间传输数据的编解码器。

它不拥有四个相邻的问题,每个问题由各自的能力负责:

  • 输入是否根本不受信任,因此必须被检查——这是应用安全能力做出的判断。此技能假定该判断已做出,并说明 Zod 如何执行它。
  • 存在一个钩子供解析调用放置于其中——路由处理器、服务端函数、表单操作——这是框架能力的事实。
  • 获取的负载何时被重新获取、缓存或失效——这是服务端状态能力的关注点。此技能仅在被其拥有的查询函数内部放入解析调用。
  • 组件如何接收、渲染和针对解析结果进行测试——这是组件开发能力的关注点。

当此处的规则与上述任何一项有对应关系时,此技能会陈述 Zod 机制并指定其他方为所有者。

版本规范。 此技能仅针对 Zod 4 编写。Zod 3 作为支持的版本线已超出范围:无迁移路径,无 zod/v3 指南,且未以其 Zod 3 形式陈述任何规则。Zod 3 出现的唯一位置是作为检测信号——一份过时惯用法的列表,以便识别过时的代码并替换为当前形式。这是一个关于 Zod 4 代码库的 Zod 4 规则,而非对 Zod 3 的覆盖。这个边界此时比平时更重要,因为跨教程、论坛帖子和模型召回,Zod 3 的答案仍然优于 Zod 4 的答案——并且大多数 Zod 3 惯用法在 Zod 4 安装下仍然可以编译,因此“它能运行”不能证明规则是当前的。Zod 4 在其主要版本内也在变动:z.xor、z.invertCodec 和 .brand 方向参数都是在 4.0 之后才出现的。这里每个对版本敏感的陈述都指明了其验证的目标,并且已知会变动的表面上的规则是查找——查阅已安装版本的官方文档 https://zod.dev/——而不是一个固定的 API 名称。将此技能或其他任何地方关于 Zod API 的未经版本限定的声明视为可疑。

已针对 [email protected](发布于 2026-05-04)验证——https://zod.dev/——前提条件为 TypeScript 5.5+ 和 strict: true。每个参考文件都带有其自己的“已针对”行,表明其规则所依据的上游页面。

超出范围。 任何形式的 Zod 3。4.5.0-canary 版本线,没有规则是基于它推导的。其他验证库,除非其与一个共享边界——覆盖了 Standard Schema 的互操作,但不覆盖 Valibot 或 ArkType 自身的 API。对于发出 Zod schema 的代码生成工具,它们被提及是为了说明它们改变了哪些你仍需手写的内容,但其自身的配置还是归它们所有。

本文件中的关键词“必须”、“不得”、“需要”、“应”、“不应”、“推荐”、“可以”和“可选”应按照 RFC 2119 中的描述进行解释。

验证边界

请参阅 validation-boundary.md 了解:

  • 在数据进入的边缘进行一次解析,并且在其内部从不重新解析
  • 解析上游的 unknown 和下游的 z.infer<typeof Schema>,绝不使用手写接口
  • 哪些问题属于应用安全、框架、服务端状态或组件能力
  • schema 带来成本而无收益的情况——内部数据、已解析的值、逐项循环
  • 在 Zod 旁边运行第二个验证器,并在一个地方进行转换

版本与包

请参阅 version-and-packages.md 了解:

  • 在信任页面之前区分 zod.dev(Zod 4)和 v3.zod.dev(Zod 3)
  • 在 zod、zod/mini、zod/locales 和 zod/v4/* 永久链接之间进行选择
  • 假设的 TypeScript 5.5+ 和 strict: true,没有它们,推断出的可选性是不健全的
  • z.xor、z.invertCodec、.safeExtend、z.property 和 .brand 方向的次版本底线
  • 仍然在 Zod 4 下编译的 Zod 3 惯用法,作为过时信号

Schema 模块

请参阅 schema-modules.md 了解:

  • const X / type X 和 zX 的命名约定,以及为每个仓库选择一个
  • 共享的 EntityId、Timestamp 和 NonEmptyString 原语,作为其他 schema 组合的词汇表
  • .brand<"Name">()、其 "out"/"in"/"inout" 方向,以及强制通过解析的 fixtures
  • 使用 .shape、.extend、.safeExtend、.pick、.omit 以及 .merge() 在 4.4 中对 refinements 的抛出进行派生
  • 将每个 schema 提升到模块作用域,而不是每次请求或渲染时重新构建

原语与格式

请参阅 primitives-and-formats.md 了解:

  • 取代了 z.string().x() 方法的顶级 z.email()、z.url()、z.uuid() 和 z.iso.datetime()
  • 选择严格的 z.uuid() 而非宽松的 z.guid(),以及选择 z.httpUrl() 而非 z.url() 来处理获取的 URL
  • 为项目自身格式使用 z.stringFormat(),为模板字面量类型使用 z.templateLiteral()
  • z.int() 的安全整数范围、对 Infinity 的拒绝,以及固定宽度的 z.int32() 和 z.float64()
  • 优先使用 z.enum() 而非已弃用的 z.nativeEnum(),以及 .exclude() 和 .extract()

对象与集合

请参阅 objects-and-collections.md 了解:

  • z.object() 会剥离未建模的键,以及 z.strictObject()、z.looseObject() 和 .catchall() 如何改变这一行为
  • 通过 getter 进行自引用,以及循环性错误所需的返回类型注解
  • z.record() 的两个必需参数、详尽的枚举键,以及 z.partialRecord()
  • z.tuple() 中 .nonempty() 不再产生元组类型,以及 z.file() 和 z.json()
  • 解析一次数组 schema 而不是对每个元素解析一项 schema

联合

请参阅 unions.md 了解:

  • 使用 z.discriminatedUnion() 进行窄化、提升错误质量以及比普通 z.union() 更快的解析速度
  • 每个分支必须固定的字面量判别器,以及 Zod 4 允许在其内部使用的嵌套联合和管道
  • 当匹配两个分支的值是一个缺陷时,使用 z.xor()
  • z.intersection() 在无法合并的结果上抛出普通的 Error 而非 ZodError
  • 本应是一个对象的可选字段形状的联合

可选性与默认值

请参阅 optionality-and-defaults.md 了解:

  • 根据生产者实际发出的内容,选择 .optional()、.nullable() 或 .nullish()
  • .default() 在输出类型上短路,而 .prefault() 在输入类型上解析
  • .catch() 将解析失败转为回退值,以及何时这隐藏了一个漂移的生产者
  • 使用 .nullish().transform((v) => v ?? null) 来折叠混合了 null 和 undefined 的生产者
  • exactOptionalPropertyTypes 对可选属性推断类型的影响

细化

请参阅 refinements.md 了解:

  • .refine()、.superRefine() 和 .check(),以及它们都不得抛出的规则
  • ctx.addIssue()、z.NEVER 以及将错误定位到特定字段的 path
  • 使用 abort 停止链,以及 4.4 的 when 跳过输入已无效的检查
  • 异步细化强制组合 schema 的每个现有调用者使用 .parseAsync()
  • 属于领域而非 schema 的权限、配额或唯一性规则

转换与管道

请参阅 transforms-and-pipes.md 了解:

  • 验证后的 .transform()、验证前的 z.preprocess(),以及两个 schema 之间的 .pipe()
  • 值改变但类型及其可内省性不得改变时的 .overwrite()
  • z.input 与 z.output/z.infer,以及混淆它们导致的表单和 fixture 错误
  • 使用 ctx.issues.push 或 4.4 中的 ctx.addIssue 配合 z.NEVER 从转换内部失败
  • 重塑生产者数据的结束点和领域决策的开始点

编解码器

请参阅 codecs.md 了解:

  • 为 .transform() 无法逆转的边界使用 z.codec(input, output, { decode, encode })
  • .decode() 和 .encode() 及其 safe* 和 *Async 形式,以及 z.invertCodec()
  • 已记录的 isoDatetimeToDate、json、stringToURL 和 base64ToBytes 模板——复制,而非导入
  • 默认值和 .catch() 仅应用于解码,而 .transform() 使编码抛出非 ZodError
  • 不会失败的总编解码器,以及因此它不提供的形状保证

强制转换与配置

请参阅 coercion-and-config.md 了解:

  • z.coerce.number().parse("") 返回 0,以及 z.coerce.boolean().parse("false") 返回 true
  • z.stringbool() 作为拒绝既不在真值集也不在假值集中的值的构造
  • 查询字符串、表单数据和环境变量作为三个字符串值来源
  • 在启动时一次性解析配置,并终止而非稍后返回 undefined
  • 将密钥配置排除在日志和客户端包之外

解析

请参阅 parsing.md 了解:

  • 当失败是缺陷时使用 .parse(),当失败是需要分支的结果时使用 .safeParse()
  • 一旦 schema 中的任何检查是异步的,.parseAsync() 就是强制性的而非可选的
  • 解析返回的深拷贝,以及由此打破的引用同一性
  • 将 ZodError 重新映射为领域错误,以便 Zod 不进入领域签名
  • 记录边界和问题路径,绝不记录失败的输入

错误

请参阅 errors.md 了解:

  • 包含 code 和 path 的 error.issues,以及已丢弃的 .errors 和 .formErrors 别名
  • 由消费者选择的 z.treeifyError()、z.flattenError() 和 z.prettifyError()
  • 取代了 message、invalid_type_error 和 errorMap 的统一 error 参数
  • 在 Zod 4 中反转的优先级——schema、每次解析、z.config({ customError })、locale
  • reportInput 将不受信任的输入放入会传递到跟踪器或客户端的错误中

元数据与 JSON Schema

请参阅 metadata-and-json-schema.md 了解:

  • .meta()、z.registry()、z.globalRegistry,以及通过声明合并扩展 GlobalMeta
  • 元数据绑定到 schema 实例,因此 .optional() 或 .extend() 会孤立它
  • z.toJSONSchema() 的 target、io、unrepresentable、cycles、reused 和 uri 选项
  • io: "input" 产生与默认输出视图不同的文档
  • 没有 JSON Schema 表示的 date、map、set、transform 和 bigint 类型

模型结构化输出

请参阅 model-structured-output.md 了解:

  • 将 schema 作为 generateObject 或工具契约,以及在需要原始形状时使用 satisfies z.ZodRawShape
  • .describe() 文本作为指令而非文档到达模型
  • 在提供者的严格模式下,.nullable() 能够存活,而 .optional() 和 .nullish() 被拒绝
  • 重用 .shape.field,以使模型输出不会偏离其供给的领域类型
  • 在有限重试次数下从 ZodError 重新提示,而不是修补无效输出

表单

请参阅 forms.md 了解:

  • 对于 Zod 自身的详细问题,使用 Zod 特定解析器;对于库独立性,使用 Standard Schema 解析器
  • 使用 z.input 获取表单的值和默认值,使用 z.output 获取提交处理器
  • 跨字段细化上的 path 是错误到达正确输入的唯一途径
  • 空白数字字段提交的空字符串,以及未选中复选框发送的缺失键
  • 客户端 schema 永远无法替代的服务端重新解析

数据存储边界

请参阅 data-store-boundaries.md 了解:

  • 存储形状和领域模型作为两个 schema,它们之间有一个转换
  • 读写两半作为一个配对编写,以便重命名的字段不会在它们之间漂移
  • 对于补丁使用 .partial(),对于携带存储哨兵创建的输入使用 .omit().extend()
  • 对于驱动程序自身类型使用 z.instanceof(),对于约束其字段之一使用 z.property()
  • 负载随查询深度、草稿状态或语言环境而变化——以及这不是答案的全可选 schema

性能与占用空间

请参阅 performance-and-footprint.md 了解:

  • 已发布的约 14 倍、约 7 倍和约 6.5 倍的解析性能提升,以及约 25,000 到约 175 的类型实例化下降
  • zod/mini 的函数式 API 和 1.88 kB 核心,以及为什么服务器不应采用它
  • 从热点路径中提升的 schema 构建,以及一次解析集合而非每个项目一次
  • 在测量的路径上,优先使用 .check() 而非 .refine(),以及优先使用判别联合而非线性联合
  • z.looseObject() 跳过键剥离过程,以及因此而放弃的保护

安全态势

请参阅 security-posture.md 了解:

  • z.object() 的剥离作为批量赋值保护,以及 z.looseObject() 重新允许了什么
  • 通过解析并不是 HTML 转义、SQL 参数化或安全获取保证
  • 将 .max() 放在 .regex() 或昂贵细化之前,以限制攻击者控制的工作
  • 无界数组、无界递归深度以及永远循环的循环输入
  • 一个白名单响应 schema,没有它,私有字段会随负载一起离开

测试 Schema

请参阅 testing-schemas.md 了解:

  • 为什么断言 z.email() 拒绝 "nope" 测试的是 Zod 而非 schema
  • 使用 z.input<typeof Schema> 作为 fixture 类型,从观察到的负载构建

…

[为翻译而截断]

相关技能