Communitygithub.com

Zod Schema

一個關於 Zod Schema 開發的意見領袖級技能庫。

Zod Schema 是什麼?

這個技能(Skill)定義了一套關於使用 Zod Schema 的嚴謹規範與最佳實踐,主要針對 Zod 4 版本。它詳細說明了 Schema 層級的擁有權,包括形狀定義、解析呼叫、型別推導、錯誤處理,以及在線路格式與領域模型間傳遞資料的編解碼器。此技能明確界定了其職責範圍,不涵蓋輸入信任判斷、框架鉤子、伺服器狀態管理或元件開發等相鄰領域,並將這些問題歸屬於其他相應的能力。文件包含多個參考章節,深入探討驗證邊界、版本與套件管理、Schema 模組化、基本型別與格式、物件與集合、聯合型別、可選性與預設值、細化規則、轉換與管道、編解碼器、強制轉型與配置、解析策略、錯誤處理、中繼資料與 JSON Schema、模型結構化輸出、表單處理、資料儲存邊界、效能最佳化、安全防護以及 Schema 測試等面向。此技能特別強調版本紀律,僅支援 Zod 4,並將 Zod 3 視為過時且需被偵測與取代的程式碼,同時也提醒注意 Zod 4 次版本間的 API 變動。

相容平台~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 的程式碼生成工具,在它們改變你仍需手動編寫的內容時會被提及,但它們自身的配置則歸它們所有。

本文檔中的關鍵詞『必須 (MUST)』、『不得 (MUST NOT)』、『必要 (REQUIRED)』、『應 (SHALL)』、『不應 (SHALL NOT)』、『建議 (SHOULD)』、『不建議 (SHOULD NOT)』、『推薦 (RECOMMENDED)』、『可以 (MAY)』和『可選 (OPTIONAL)』應按照 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" 方向,以及它強制通過解析的固定資料
  • 使用 .shape、.extend、.safeExtend、.pick、.omit 和 .merge()(4.4 版在細化上會拋出錯誤)進行衍生
  • 將每個 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,以及混淆兩者導致的表單和固定資料錯誤
  • 使用 ctx.issues.push 或 4.4 版的 ctx.addIssue 搭配 z.NEVER 從轉換內部觸發失敗
  • 重塑生產者資料的結束點與領域決策的起始點

編解碼器

詳見 codecs.md:

  • 使用 z.codec(input, output, { decode, encode }) 處理邊界 .transform() 無法反向的情況
  • .decode() 和 .encode() 及其 safe* 和 *Async 形式,以及 z.invertCodec()
  • 已記錄的 isoDatetimeToDate、json、stringToURL 和 base64ToBytes 模板——複製,而非匯入
  • 僅在解碼時套用的預設值和 .catch(),以及會使編碼拋出非 ZodError 的 .transform()
  • 不會失敗的完整編解碼器,以及它因此無法提供的形狀保證

強制轉型與配置

詳見 coercion-and-config.md:

  • z.coerce.number().parse("") 回傳 0,以及 z.coerce.boolean().parse("false") 回傳 true
  • z.stringbool() 作為拒絕既不為真亦不為假值(truthy/falsy)的建構
  • 查詢字串、表單資料和環境變數作為三個字串值來源
  • 在啟動時解析一次配置並終止,而不是稍後回傳 undefined
  • 將秘密配置排除在日誌和客戶端 bundle 之外

解析

詳見 parsing.md:

  • 當失敗是缺陷時使用 .parse(),當失敗是需要分支的結果時使用 .safeParse()
  • 一旦 Schema 中有任何檢查是非同步,.parseAsync() 就是強制的而非可選的
  • 解析回傳的深層克隆,以及它因此打破的參考身分
  • 將 ZodError 重新對應到領域錯誤,使 Zod 遠離領域簽名
  • 記錄邊界和問題路徑,絕不記錄失敗的輸入

錯誤

詳見 errors.md:

  • error.issues 及其 code 和 path,以及已捨棄的 .errors 和 .formErrors 別名
  • 由消費者選擇的 z.treeifyError()、z.flattenError() 和 z.prettifyError()
  • 取代 message、invalid_type_error 和 errorMap 的統一 error 參數
  • 在 Zod 4 中反轉的優先順序——Schema、每次解析、z.config({ customError })、語言環境
  • 使用 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:

  • 作為 generateObject 或工具合約的 Schema,以及在需要原始形狀時使用 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> 作為固定資料型別,從觀察到的承載建構

...

相關技能