JSON 轉 Zod Schema 轉換器是一個瀏覽器端工具,可將一個有效的 JSON 值轉換成可讀且已去重的 Zod 原始碼,並推導出一個 TypeScript 型別。它採用嚴格的 JSON 解析與有文件記載的推導規則,並對猜測的內容設有明確的上限。這個頁面不會載入 Zod、不會執行產生的程式碼,也不會上傳你的範例資料;它會解析嚴格的 JSON、遞迴走訪結構,並輸出一份穩定的文字表示,讓你複製到自己的專案中。
這套轉換遵循一小組有文件記載的規則。原始 JSON 值會對應到相應的 Zod 建構函式:字串對應 z.string()、有限的 JSON 數字對應 z.number()、布林值對應 z.boolean()、null 對應 z.null()。物件鍵會依照原始碼出現的順序排列,合法的 JavaScript 識別字不加引號,而不安全的名稱(含空格、連字符、以數字開頭、引號)則會以 JSON 字串跳脫方式輸出,確保產生的結構仍是合法的原始碼。陣列會根據輸入預算中每個元素進行推導:同質的樣本會產生單一元素 schema,混合樣本會產生確定性的 z.union,空陣列則刻意產生 z.array(z.unknown()),因為沒有元素型別的證據。巢狀陣列與物件會以遞迴方式處理;當陣列中包含物件時,這些物件的鍵會合併成單一結構。

轉換器如何將 JSON 對應到 Zod 原始碼
推導引擎分三個可預測的階段執行。首先,輸入字串會以嚴格的 JSON 規則進行解析;JavaScript 註解、尾端逗號、NaN、Infinity、undefined、BigInt 語法、單引號字串,以及物件實字會被拒絕,而不是悄悄地被修復。其次,解析後的樹會以遞迴方式走訪,每個節點使用上述有文件記載的建構函式對應到一個 Zod 表示式。第三,相同的 schema 會被去重,混合值的聯集會以確定性的方式排序,因此對同一份 JSON 轉換兩次會產生位元穩定的原始碼。
合併規則是最讓大多數讀者感到意外的部分。當陣列中包含多個物件樣本時,轉換器會合併它們的鍵:在每個取樣物件中都出現的屬性會保持必填,而在至少一個物件中缺少的屬性則會變成 .optional()。同一個鍵下觀察到的值會以遞迴方式合併,因此一個有時是 null、有時是字串的屬性會變成 z.string().nullable(),而有時是字串、有時是物件的屬性則會變成 z.union([z.string(), z.object({...})])。這些規則適用於每一層巢狀,而不僅限於根層級。
從一個 JSON 樣本產生 Zod schema
下面的工作流程反映了三個有文件記載的操作步驟,以及你在將 schema 合併進真實程式碼庫之前應該加入的驗證迴圈。
- 將一個有效且具代表性的 JSON 值(物件、陣列或原始值)貼上轉換器,然後輸入一個合法的 JavaScript 識別字作為 schema 名稱。這個識別字不可以是保留字,且必須遵循標準的 JavaScript 命名規則。
- 產生 Zod 原始碼,然後檢查工具所做的每一項決定:可選欄位、可空聯集、混合陣列聯集、空陣列、數字精度,以及針對不安全屬性名稱的引號鍵。這些都是推導,而不是合約證明。
- 將輸出的原始碼複製到已安裝 Zod 的專案中,格式化、編譯,並使用涵蓋通過與拒絕案例的測試資料,對其進行權威資料合約的測試。這個頁面不會安裝 Zod 或執行驗證;那一步發生在你的專案中。
轉換器刻意不會推導的內容
採用推導而得的 schema 時,最常見的錯誤就是將它視為完整的合約。產生器拒絕捏造單一樣本無法建立的規則,相關的推理在探討產生的 Zod schema 是否能證明 API 合約的專文中有進一步討論。
| JSON 觀察結果 | 推導的 Zod 輸出 | 必須手動加入的內容 |
|---|---|---|
| 字串值 | z.string() | 格式(email、URL、UUID)、最小與最大長度、正則表示式、字面值 |
| 有限的 JSON 數字 | z.number() | 整數檢查 (.int())、最小值、最大值、有限值、multipleOf |
| 布林值 | z.boolean() | 字面值約束、自訂 refinements |
| null 與其他型別並存 | <type>.nullable() | 該欄位是否也可以省略 (.optional()) |
| 空陣列 | z.array(z.unknown()) | 真實的元素型別、最小與最大長度 |
| 混合的原始值陣列 | z.array(z.union([...])) | 鑑別子(discriminator)、字面值標籤、brand |
| 鍵一致的物件 | z.object({...}) | .strict()、.passthrough()、.catchall()、預設值、轉換 |
| 需要精確十進位語意的數字 | z.number() | 針對貨幣、識別字與高精度小數保留為字串 |
一般規則很簡單:拼寫與小樣本無法確立意圖。如果你的合約保證為整數或列舉字面值,請依據權威文件與更廣泛的測試資料自行撰寫該約束。
從合併樣本決定必填、可選與可空欄位
必填與可選是逐鍵決定的,方式是比對樣本陣列中的每個物件(以及遞迴走訪時遇到的每個巢狀物件)。在 100% 樣本物件中都出現的鍵會保持必填;在任何樣本中缺少的鍵會變成 .optional()。這裡是真實合約最有可能與推導而得的 schema 產生分歧的地方:在一個範例中出現的欄位在生產環境中仍然可能是可選的,而在樣本中缺少的值也完全可能是合法的。
可空性以對稱的方式決定。如果在某個鍵下曾經觀察到 null 與其他型別並存,推導而得的 schema 會變成 <type>.nullable()。如果在某個鍵下唯一觀察到的值是 null,schema 則會變成 z.null()。不安全的屬性名稱會以 JSON 字串跳脫加上引號,使得像 "first name" 這樣的鍵能夠完整地往返轉換為合法的 JavaScript 原始碼。同樣的跳脫規則也適用於以數字開頭、含有連字符,或含有其他會破壞物件實字之字元的鍵。
必須知道的輸入限制與解析規則
轉換器受到四項硬性上限約束,外加從 JSON 解析器繼承而來的精度。超過上限會回傳明確的錯誤,且絕不會輸出部分的 schema。即使沒有觸及這些上限,過深或過寬的範例仍然可能是不良的合約文件,因此請優先使用小而具代表性的測試資料,並將獨立的負載拆分成各自的 schema。
| 上限 | 值 | 超過時的效果 |
|---|---|---|
| 輸入字元數 | 500,000 | 明確錯誤,無輸出 |
| 推導過程中造訪的值數 | 50,000 | 明確錯誤,無輸出 |
| 巢狀深度 | 40 | 明確錯誤,無輸出 |
| 產生原始碼的字元數 | 1,000,000 | 明確錯誤,無輸出 |
| JavaScript 數字精度 | 繼承自 JSON.parse | 高精度小數會喪失精度;請改用字串 |
複製之後:安裝、格式化、編譯、測試
這個頁面只輸出原始碼文字。接著依序進行三件事。首先,在你的目標專案中安裝並固定你預期的 Zod 版本;位於 zod.dev/api 的官方建構函式參考文件列出了產生原始碼中可能出現的每一個表示式,而Zod 原始碼儲存庫則固定了目前的釋出版本。其次,使用你專案的格式化工具格式化原始碼,並確認它能在 TypeScript 下編譯。第三,執行一套聚焦的測試套件,涵蓋你的測試資料所展示的通過案例,以及你的權威文件所禁止的拒絕案例(多餘欄位、缺少必填欄位、錯誤型別、超出範圍的值)。只有在這套測試通過之後,推導而得的 schema 才適合接入請求驗證器、表單 schema 或 API 回應守衛。
由於同一份 JSON 在重複執行時會產生穩定的原始碼,這個轉換器非常適合用於文件驅動的工作流程:貼上一份真實的負載,將產生的 schema 擷取為起始檔案,然後依據合約實際要求的規則加以收緊。