GraphQL Codegen 是什麼?從零開始了解自動化產生 TypeScript 型別的神器
更新日期: 2025 年 5 月 10 日
在開發使用 GraphQL 的前後端系統時,常見挑戰之一就是「維護型別一致性」。
當你在後端定義了一份 GraphQL schema,前端開發者也需要手動撰寫對應的型別定義,這不僅麻煩,還容易出錯。
更別提當 API 改動時,前端型別沒有同步更新的情況,可能會導致整個應用在執行階段發生錯誤。
這時候,GraphQL Code Generator(簡稱 GraphQL Codegen) 就成了你的救星。
這是一個能夠根據 GraphQL Schema 自動生成 TypeScript 型別、Hooks、甚至整個 API 查詢函式的工具,大幅提升開發效率與安全性。
為什麼前端開發要關心型別?從 interface
與資料格式說起
在前端開發中,我們經常需要處理從 API 回傳的資料。
這些資料幾乎都採用 JSON 格式,也就是 JavaScript 的物件(object)結構:
{
"id": 1,
"name": "Alice",
"email": "[email protected]"
}
這種 key-value 的資料表示方式,不只易讀、易傳輸,也與 JavaScript 完美相容,因此成為 API 回傳的標準格式。
即便是 GraphQL 查詢的結果,最外層也總是被包裝成物件,例如:
{
"data": {
"user": {
"id": "1",
"name": "Bob"
}
}
}
所以從實務角度來看,前端開發者處理的資料幾乎一定是「物件格式」。
而為了能正確操作這些資料並避免錯誤,我們就需要一種方法,明確描述「這個物件應該包含哪些欄位、各是什麼型別」。
TypeScript 的 interface
:為資料定義規格書
在 TypeScript 中,這樣的「規格書」就是用 interface
來寫的。
例如:
interface User {
id: string;
name: string;
email?: string;
}
這代表:User
是一個物件型別,應該有 id
和 name
(都是字串),email
則是可選欄位。
使用 interface
有幾個好處:
- 編輯器會提供欄位補全與型別提示
- TypeScript 可以在開發階段主動幫你檢查資料結構是否正確
- 同一組資料可以被多個元件、安全重複使用
簡單來說,interface
幫助我們在處理 API 回傳資料時,強化型別安全、提升開發效率。
問題來了:前後端的資料型別是分開維護的
假設你在後端使用 GraphQL 定義了一個 User
:
type User {
id: ID!
name: String!
email: String
}
而在前端,你又用 TypeScript 再定義一次幾乎一模一樣的 interface
:
interface User {
id: string;
name: string;
email?: string;
}
這裡的問題是,這兩份型別定義彼此獨立、完全沒有連動。
只要後端改了一個欄位名稱,或是多加了一個欄位,如果前端沒發現,就會發生執行時錯誤。
例如畫面取不到 email
資料、變成 undefined
,甚至造成整個元件渲染失敗。
在小專案時,手動維護型別還算 manageable;但在大型應用、多人開發的情境下,這種型別不同步的情況非常容易發生,也很難追蹤。
型別同步的重工問題,正在拖累你的開發效率
回到實際開發流程,每當你新增一個 GraphQL 查詢,從後端拿資料時,你就必須:
- 撰寫查詢語法
- 預測資料回傳的欄位與型別
- 手動寫出對應的 TypeScript interface
- 如果未來欄位變更,再回來手動更新型別
這過程充滿重複、容易出錯,而且完全無法保證正確。
更糟的是,TypeScript 本身無法知道 API 實際回傳了什麼,它只會照你手動寫的型別去檢查。如果你寫錯了,錯的也只是你自己定義的型別,和實際回傳的資料根本無法對照。
解法:讓工具幫你自動同步前後端型別
前面提到的所有型別同步問題,其實都可以透過一個工具來解決 —— 那就是 GraphQL Code Generator(簡稱 GraphQL Codegen)。
這個工具的核心功能,就是自動化產出 TypeScript 型別與查詢相關函式,讓前端開發者不再需要手動撰寫、更新或同步資料結構。
換句話說,它把「GraphQL Schema」這份契約轉譯成你實際可以在程式中使用的型別與函式。
它根據什麼產生程式碼?
GraphQL Codegen 能自動產生 TypeScript 型別與開發函式的關鍵,來自於它可以「讀懂」兩種來源的資訊:GraphQL Schema 和 查詢語法。
這兩者缺一不可。
GraphQL Schema(通常是後端提供)
GraphQL Schema 是一份完整描述後端資料結構的「API 說明書」。
用來定義整個系統中,有哪些可查詢的資料型別(types)、每個型別有哪些欄位、每個欄位的資料型別、是否必填(nullable)、可傳入哪些參數等。
範例如下:
type User {
id: ID!
name: String!
email: String
}
type Query {
user(id: ID!): User
}
這段 schema 表示:
User
是一種資料型別,擁有id
,name
,email
三個欄位id
和name
是必填欄位(!
表示非 null)Query.user
是一個查詢,接收一個id
參數,回傳對應的User
📌 對 GraphQL Codegen 來說,Schema 提供了「全域的型別來源」,讓它能了解每個查詢背後的資料結構、欄位型別與對應關係。
你可以從以下地方取得 Schema:
- 後端提供的
.graphql
檔案 - GraphQL 伺服器的 introspection endpoint(通常是
/graphql
) - 也可以直接從遠端 API 抓下來使用
GraphQL 查詢語法(Query / Mutation / Fragment)
除了知道 API 整體長什麼樣,Codegen 還需要知道「你實際用到什麼」。
這就是查詢語法的角色。
你在前端專案中撰寫的 .graphql
查詢檔案,像這樣:
# getUser.graphql
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
這段查詢表示你會呼叫 user(id: $id)
這個 API,並且只取回 id
, name
, email
三個欄位。
📌 對 Codegen 而言,這些查詢語法提供了「實際使用情境」的上下文,它會分析:
- 查詢名稱與變數(例如
$id
是什麼型別) - 要抓哪些欄位(不會產生沒用到的欄位)
- 是否用到 fragment(模組化的欄位結構)
根據這些資訊,它就能產生出:
- 查詢變數的型別(
GetUserQueryVariables
) - 查詢結果資料的型別(
GetUserQuery
) - 搭配框架用的函式(如 React 的 Hook)
🧠 小結
來源 | 提供的資訊 | Codegen 如何使用 |
---|---|---|
GraphQL Schema | API 的結構說明(type, field) | 了解資料整體型別,決定欄位該有哪些型別 |
查詢語法 | 實際使用哪些欄位與變數 | 根據查詢內容產生「實際需要的型別與函式」 |
透過這種方式,Codegen 能確保你產出的程式碼「不多也不少」──只產生你實際需要用的查詢欄位的型別,而且與後端定義完全同步。
如果你有設定 watch
模式,每次你修改查詢語法或後端 schema。
只要重新執行 Codegen,前端的 TypeScript 型別就會自動更新,不需再手動修改任何 interface,從此告別型別不同步的問題。
它可以幫你產出什麼?
GraphQL Codegen 最常見的產出內容包括:
產出內容 | 說明 |
---|---|
✅ TypeScript 型別 | 根據 Schema 自動產出資料結構的 interface,無需手動維護 |
✅ Query 回傳型別 | 每個查詢的回傳結果會有精確型別,例如 GetUserQuery |
✅ Query 變數型別 | 查詢中使用的變數也會產出對應型別,例如 GetUserQueryVariables |
✅ React Hook 函式 | 搭配 Apollo Client 使用時,自動產生如 useGetUserQuery() 的查詢函式 |
✅ SDK(可選) | 如果選擇產出 SDK,可以得到封裝好的函式,例如 sdk.getUser({ id }) |
這些產出的程式碼都是型別安全、零手動撰寫、可直接使用的程式碼片段,可以立即用在元件中,並享有完整補全提示與錯誤檢查。
📦 實際例子:從查詢語法到型別與 Hook
假設你有一份查詢:
# src/queries/getUser.graphql
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
經過 Codegen 處理後,它會自動幫你產出這些東西:
// 自動產出的查詢型別
export interface GetUserQuery {
user?: {
id: string;
name: string;
email?: string;
} | null;
}
// 自動產出的變數型別
export interface GetUserQueryVariables {
id: string;
}
// 搭配 Apollo Client 自動產出的 Hook
export function useGetUserQuery(options: QueryHookOptions<GetUserQuery, GetUserQueryVariables>) {
// ...
}
你只需要這樣寫,就可以正確、安全地拿到資料:
const { data } = useGetUserQuery({ variables: { id: "123" } });
console.log(data?.user?.name); // 編輯器自動提示 user.name 是 string
快速開始:如何使用 GraphQL Codegen?
如果你已經在專案中使用 GraphQL,並希望自動產出 TypeScript 型別與查詢函式,那麼接下來的步驟將帶你快速建立一套完整的 GraphQL Codegen 開發流程。
以下以最常見的情境為例:
前端使用 React + Apollo Client,撰寫 GraphQL 查詢並希望產出對應的型別與 Hook 函式。
第一步:安裝 GraphQL Codegen CLI 工具
GraphQL Codegen 提供一個 CLI 工具,讓你能以命令列方式執行程式碼產生的動作。
你可以透過 Yarn 或 npm 安裝在專案中:
# 使用 Yarn
yarn add -D @graphql-codegen/cli
# 或使用 npm
npm install --save-dev @graphql-codegen/cli
這會將 CLI 工具安裝為開發依賴,供你在本地端執行 codegen
指令。
第二步:初始化設定檔(codegen.yml
)
安裝完 CLI 工具後,執行以下指令來建立設定流程:
npx graphql-codegen init
這個初始化精靈會一步一步詢問你一些問題,並根據你的選擇建立一份設定檔 codegen.yml
,裡面定義了 Codegen 的所有行為。
常見選項包括:
問題項目 | 說明 |
---|---|
Schema 來源 | 指定 GraphQL Schema 的位置(本地 .graphql 檔或遠端 URL) |
文件來源 | 指定你撰寫的查詢檔案路徑(如 src/**/*.graphql) |
Plugin 選擇 | 決定你想產生什麼樣的 TypeScript 型別與整合函式 |
輸出位置 | 指定產出的型別檔案應該存放在哪裡(如 src/generated/graphql.ts) |
設定完成後會自動建立一份 codegen.yml
檔案,例如:
overwrite: true
schema: http://localhost:4000/graphql
documents: src/**/*.graphql
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
這表示:
- Codegen 會從
/graphql
抓取 Schema - 找出
src/
底下所有的.graphql
查詢檔 - 產生 TypeScript 型別與 React Hook,寫入
src/generated/graphql.ts
第三步:常見 Plugin 說明
GraphQL Codegen 採用 plugin 機制,讓你可以自由選擇要產出哪些內容。以下是幾個最常見、最實用的 plugin:
Plugin 名稱 | 說明 | 適用情境 |
---|---|---|
typescript | 根據 Schema 產出所有 TypeScript 型別(如 User, Post) | 基礎型別定義 |
typescript-operations | 根據查詢語法,產生查詢結果與變數的型別(如 GetUserQuery, GetUserVariables) | 查詢型別推論 |
typescript-react-apollo | 自動產生 React Hook,如 useGetUserQuery,整合 Apollo Client 用法 | React + Apollo 使用者 |
typed-document-node | 產出型別化的查詢文件,可搭配 React Query、Urql 等使用 | 進階整合場景或 client-agnostic 專案 |
這些 plugin 可以搭配使用。例如你可以同時使用 typescript
, typescript-operations
, typescript-react-apollo
,產出完整的資料模型與查詢工具。
第四步:執行程式碼產生
完成設定後,只需執行以下指令即可產出型別與函式:
npx graphql-codegen
或在 package.json
中加入 script:
{
"scripts": {
"codegen": "graphql-codegen"
}
}
然後以更簡單的方式執行:
yarn codegen
選配:自動監聽 .graphql
檔案變動
你可以啟用 watch 模式,讓程式在檔案變更時自動重新產生型別:
npx graphql-codegen --watch
這樣每次你新增或修改查詢語法,Codegen 都會即時更新對應的型別與 Hook。
範例整合:用 React 搭配 Apollo Client 自動呼叫查詢
當你完成 GraphQL Codegen 設定並執行完產生後,它會為你自動生成許多便利的 TypeScript 型別與查詢工具。
若你使用的是 React 且搭配 Apollo Client,還能自動幫你產出 查詢 Hook 函式(例如:useGetUserQuery
),讓你只要寫一行就能安全、快速地呼叫 API,完全不用手動寫 fetch 或 .gql
查詢語法。
以下是一個完整的整合範例,展示如何用這些產生出來的工具,在 React 元件中進行查詢:
自動產生的查詢 Hook:useGetUserQuery
import { useGetUserQuery } from '../generated/graphql';
這一行匯入的是 Codegen 自動產生的 React Hook。
它根據你在 getUser.graphql
檔案中寫的查詢內容(例如 query GetUser($id: ID!) { user(id: $id) { name, email } }
)而生成,內含型別資訊、查詢邏輯與 Apollo 整合。
元件範例:使用查詢 Hook 串接資料
const Profile = () => {
const { data, loading, error } = useGetUserQuery({
variables: { id: '123' }
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return (
<div>
<h1>{data?.user?.name}</h1>
<p>{data?.user?.email}</p>
</div>
);
};
這段元件做了幾件事:
區塊 | 功能 |
---|---|
useGetUserQuery({ variables }) | 呼叫自動產生的查詢 Hook,Apollo 會自動送出查詢 |
loading | 查詢是否還在進行中,顯示 loading 狀態 |
error | 若查詢失敗,顯示錯誤訊息(可擴寫) |
data?.user?.name | 拿到後端回傳的資料並顯示在畫面上,TypeScript 會提供自動補全 |
🧠 為什麼這麼有價值?
- 完全不需要手動寫查詢函式
不需gql
、不需寫useQuery
,Codegen 已經幫你封裝好。 - 有完整的型別提示與錯誤檢查
data.user
是從查詢分析中自動導出的型別,TypeScript 會知道欄位是否可為null
、變數是否缺少等錯誤。 - 保持查詢語法與邏輯分離
查詢寫在.graphql
檔案中,元件中只負責顯示邏輯與變數傳入,清晰又好維護。
專案目錄建議結構:
為了讓 Codegen 能順利分析與輸出查詢 Hook,你的專案目錄結構可以像這樣:
my-project/
├── src/
│ ├── components/
│ │ └── Profile.tsx
│ ├── graphql/
│ │ └── getUser.graphql
│ └── generated/
│ └── graphql.ts ← Codegen 輸出的型別與 Hook 都會集中在這裡
├── codegen.yml ← Codegen 的設定檔
你在 graphql/getUser.graphql
中寫的查詢:
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
會自動產出:
useGetUserQuery()
React HookGetUserQuery
回傳資料型別GetUserQueryVariables
查詢變數型別
GraphQL Codegen 常見問題與實務建議
在實作 GraphQL Codegen 的過程中,開發者常會遇到一些實際操作層面的問題與選擇。
例如檔案格式、Schema 來源的同步方式、與不同 GraphQL Client 的整合方式。以下是幾個最常見的問題與建議解法:
❓ 我一定要使用 .graphql
檔案嗎?
不一定,但強烈建議使用。
GraphQL 查詢語法可以透過兩種方式撰寫:
.graphql
檔案(推薦)
將查詢語法獨立成檔案,例如 src/graphql/getUser.graphql
,內容可能如下:
query GetUser($id: ID!) {
user(id: $id) {
id
name
}
}
gql
標記模板字串(常見於 JS/TS 檔案中)
將查詢直接寫在 JavaScript / TypeScript 檔案中,例如:
import { gql } from '@apollo/client';
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
}
}
`;
✅ 哪種方式比較好?
項目 | .graphql 檔案(推薦) | gql 字串方式 |
---|---|---|
可讀性 | ✅ 查詢與邏輯分離,結構清楚 | ❌ 容易混雜在 component 邏輯中 |
重複利用 | ✅ 易於共用與重構 | ❌ 重複查詢會被複製貼上 |
Codegen 相容性 | ✅ 原生支援 | ✅ 但需額外安裝 Babel 插件 |
IDE 支援 | ✅ IntelliSense 與語法高亮 | 部分支援(視 IDE 而定) |
📌 實務建議:若你使用 GraphQL Codegen,強烈建議將查詢獨立寫成 .graphql
檔案。
這不僅可讀性高,也更容易追蹤查詢改動,與 Git diff 友善,且幾乎不需要額外安裝解析器。
❓ 如果 Schema 常常變動怎麼辦?
在實務上,API 可能會因為後端更新功能、資料欄位調整等而頻繁改動。
如果前端沒有同步更新型別,就可能導致畫面錯誤或執行期異常。
以下是幾種維持 Schema 同步的做法:
✅ 定期手動更新(開發初期)
你可以在開發期間定期執行:
npx graphql-codegen
這會重新根據最新的 Schema 與查詢語法產出型別。
✅ 加入 CI/CD 自動產生
在正式團隊開發中,建議你把 Codegen 整合進 CI/CD 流程中,例如:
- 每次
pull request
時自動執行graphql-codegen
,比對產出結果是否有變動 - 或在
build
前先執行一次 Type 檢查與產生
📌 這能確保型別永遠與 Schema 同步,避免查詢邏輯過時。
✅ 從遠端 API 自動抓 Schema
若你的後端提供 introspection endpoint,例如 http://localhost:4000/graphql
,你可以在 codegen.yml
中設定:
schema: http://localhost:4000/graphql
這樣 Codegen 每次執行都會自動抓取最新的 API 結構,不需手動維護 schema 檔。
❓ GraphQL Codegen 能搭配 React Query 或其他 client 使用嗎?
可以,而且支援性很好!
GraphQL Codegen 並不只支援 Apollo Client,它支援多種 GraphQL Client,只要選用對應的 plugin 即可:
Client | 對應 Plugin | 說明 |
---|---|---|
Apollo Client | typescript-react-apollo | 自動產生 useQuery, useMutation 等 Hook |
React Query | typescript-react-query | 自動產生 useQuery, useMutation 等 react-query Hook |
Urql | typescript-urql | 支援 useQuery, useMutation 產生器 |
其他自訂 client / fetch 寫法 | typed-document-node | 產出類似 DocumentNode 結構並附上型別(中立格式) |
🧠 實務建議:
- 若你是 Apollo Client 用戶 → 選
typescript-react-apollo
,功能完整 - 若你想用 React Query(搭配 REST 或 SWR 過渡期)→ 用
typescript-react-query
- 若你是寫 SDK 或要客製化 GraphQL client → 建議使用
typed-document-node
搭配graphql-request
等函式庫
總結:為什麼初學者也該學會 GraphQL Codegen?
理由 | 說明 |
---|---|
提升開發效率 | 免去手寫型別與樣板查詢函式 |
避免執行錯誤 | 利用型別檢查提早發現問題 |
學習成本低 | 安裝 + 設定就能使用,且支援 CLI 與 GUI |
可擴充性強 | 支援眾多 plugin,符合各種開發情境 |
GraphQL Codegen 是一個既強大又實用的開發工具,尤其對使用 TypeScript 的開發者來說更是不可或缺。
初學者若能熟練這個工具,能有效提升團隊協作效率與程式碼穩定性,是進入現代前後端整合開發的絕佳第一步。