§

JSON 範例

正在準備型別推斷器…
§

TypeScript 介面

TypeScript

台灣的 TypeScript 團隊很早就會遇到這個問題。大型 SDK 提供型別化客戶端(Stripe、Twilio、AWS),但內部服務和第三方 webhook payload 很少如此,因此典型工作流程是:在網路面板中捕獲真實回應,貼入此處,以端點名稱命名根介面,然後將輸出複製到專案的型別目錄。從那時起,strict 模式就能抓到文件遺漏提及的不符。推斷器完全在你的瀏覽器中執行,因此來自測試環境 API、已簽署的 webhook 本文和尚未發布的端點 payload 都不會傳到任何代管服務。

JSON 轉 TypeScript 推斷的運作原理

推斷是對解析後的 JSON 樹的單次遍歷。工具讀取每個值,為其選取 TypeScript 型別,然後為找到的每個物件輸出一個介面。

  1. 使用瀏覽器的原生解析器解析 JSON 範例,並以行/列提示拒絕格式錯誤的輸入。
  2. 嗅探每個值的 TypeScript 型別——stringnumberbooleannull、陣列或巢套物件。
  3. 為每個巢套物件提供從其父屬性鍵衍生的介面名稱(因此 user.address 成為 Address 介面)。
  4. 合併每個陣列的項目型別,使 {id: 1}{id: 2, label: "x"} 的列表產生含正確可選欄位的聯合型別。
  5. 套用你的選項(interface 還是 type、readonly、可選-nullable),並以依賴順序輸出宣告,使檔案在沒有前向引用的情況下能編譯通過。

為何要從 JSON 產生 TypeScript 型別?

  • 大多數形狀錯誤在編譯時是可以發現的,前提是回應型別已被記錄下來。從真實 payload 推斷介面能替你寫好大部分內容,而 `strict` 模式則能抓到文件遺漏提及的欄位。
  • 將推斷的介面與 Zod 或 io-ts 等執行時驗證器配對,讓同一形狀承擔兩項工作:開發時的編輯器自動完成,以及當正式環境回傳意外內容時在邊緣觸發 400 錯誤。
  • TypeScript 語言服務器只顯示它知道的欄位。一旦你匯入推斷的介面,只要你輸入點號,自動完成就開始運作——不再需要對回應進行 `as any` 強制轉換,也不必在整個 repo 中沮喪地 grep。
  • 如果你即將撰寫 OpenAPI 規格,推斷的介面是回應 schema 的快速初稿。你仍需要手寫範例和約束條件,但屬性名稱和型別已經正確了。

常見應用場景

在真實 payload 存在但 schema 不存在時,推斷最有幫助。

  • 在撰寫處理器之前,為來自 Stripe、GitHub 或 Twilio 的第三方 webhook payload 加上型別。
  • 為內部 REST API 啟動型別,讓前端團隊在後端當天上線後就能開始根據它編寫程式碼。
  • 從觀察到的 API 回應為 Zod、io-ts 或 Valibot schema 產生起始點。

輸出長什麼樣子?

給定一個 JSON 範例文件和根名稱,產生器會產生一棵介面樹,每個巢套物件一個。對於以 User 為根名稱的以下輸入:

貼上 {"id":1,"name":"Alice","tags":["a","b"],"address":{"city":"Paris"}},根名稱設為 User,產生器會產生:

export interface User {
  id: number;
  name: string;
  tags: string[];
  address: Address;
}

export interface Address {
  city: string;
}
注意 address 被提升為自己命名的介面——這就是依賴順序輸出。以type宣告風格替換後,輸出將是 export type User = {...};開啟 readonly 切換後,每個屬性都會加上 readonly 修飾符。

產生器選項

宣告風格

選擇 interface(物件形狀的標準 TypeScript 慣用方式)或 type(如果之後需要映射型別、條件型別或交集,這更方便)。兩者產生完全相同的執行時行為;選擇是編碼風格偏好。

可選的 nullable 欄位

當取樣值為 null 時,欄位型別變為 T | null。開啟此選項後,還會加上 ? 修飾符,使欄位在 TypeScript 端為可選——當 API 有時完全省略鍵而非返回 null 時很有用。

Readonly 修飾符

在每個屬性宣告前加上 readonly,使輸出的介面符合不可變資料模型。適用於 Redux 狀態切片、凍結的 API 回應,或任何你希望編譯器標記意外變更的場合。

支援巢套物件和陣列嗎?

是的。每個巢套物件成為從其父屬性鍵衍生的命名介面,陣列從其內容推斷項目型別。物件陣列在形狀不一致時會每個物件形狀產生一個介面,並以聯合型別表示。

可選欄位是如何推斷的?

開啟「將可為 null 的欄位標記為可選」切換,任何取樣值為 null 的欄位,其鍵上會加上 ? 修飾符,型別中加上 | null。不開啟此切換時,欄位保持必要,型別僅為 T | null

支援可辨識聯合型別嗎?

當陣列包含不同形狀的項目,或欄位同時包含值與 null 時,會產生基本聯合型別。完整的可辨識聯合型別推斷(選取 typekind 作為標記並分割變體)需要多個範例——這已在計畫中但尚未在目前的版本中實作。

可以從多個 JSON 範例推斷型別嗎?

目前還不行——今日的推斷器一次讀取一個範例。如果你有兩個應該共用一個介面的 payload(例如列表端點和單個項目端點),實際的解決方法是將它們合併為一個陣列,從中產生型別,然後重新命名結果的聯合型別。多範例推斷已在路線圖上,因為這是發現某個欄位在一個回應中存在而在另一個回應中缺失的唯一方式。

貼上 payload,命名根介面,複製介面。整個流程在你的瀏覽器中執行,因此未發布的 API 或已簽署的 webhook 本文都留在你的機器上。