- Published on
Zod v4 實戰攻略 - TypeScript-First 表單驗證利器
- Authors
- Name
- Penghua Chen(PH)
本文摘要
Zod 表單驗證函式庫是近年來很熱門的表單驗證函式庫,主要可用於前端表單欄位驗證,或者是 API Request 請求時驗證欄位使用。
筆者在最近一個專案中使用到,所以撰寫筆記記錄使用心得。
本篇文章採用 Zod v4 作為文章撰寫使用的版本。
本篇文章重點:
- 為什麼覺得 Zod 值得為它撰寫文章?
- 基礎使用方式
- 前端 Demo - 以使用者建立表單為例 (使用 Vue3)
Zod 基礎使用方式

Zod 核心使用概念:
- 定義 schema (define schema)
- 解析 data (parsing data)
- 錯誤處理 (handling errors)
- 型別推導(Inferring types)
1. 定義 schema (define schema)
定義 schema 的意義是跟 Zod 說:「嘿 Zod ! 我要提供一組規則讓你知道,你必須幫我按照這個規則確認是否通過/失敗」。
以建立使用者資料為例,我們定義以下要提供的規則:
name
: 必填,使用者姓名,預設值為空字串password
: 必填,使用者密碼,密碼長度至少為 8 碼,預設值為空字串age
: 選填,使用者年齡,只能輸入數字,預設值為null
基於上面提到的情境與規則,我們可以撰寫以下 schema:
import * as z from "zod";
const UserSchema = z.object({
name: z.string().min(1, '使用者姓名為必填'),
password: z.string().min(8, '密碼長度至少需要 8 碼') ,
age: z.number().nullable().optional(),
});
2. 解析 data (parsing data)
緊接著,透過 .parse
以及傳入的 schema 定義所回傳的 user
物件進行 data 解析,如果驗證通過,會直接 return 整個 user
物件:
const UserSchema = z.object({
name: z.string().min(1, '使用者姓名為必填'),
password: z.string().min(8, '密碼長度至少需要 8 碼') ,
age: z.number().nullable().optional(),
});
const user = {
name: "PH",
password: "12345678",
age: 30
};
UserSchema.parse(user); // 如果驗證通過,會直接 return 整個 user 物件
那如果驗證沒有通過呢?
例如接下來的這個情境: user
的 name
忘記填寫了!
接著就會進入到錯誤處理步驟
3. 錯誤處理 (handling errors)
如同前面提到, user
的 name
忘記填寫,此時會發生錯誤,並拋出 ZodError
實例(instance):
const user = {
password: "12345678",
age: 30
};
UserSchema.parse(user); // 拋出 ZodError 錯誤
如果習慣使用 try/catch
實作錯誤處理的讀者,可以透過 catch(error)
進行錯誤捕捉(capture)
try {
const UserSchema = z.object({
name: z.string().min(1, '使用者姓名為必填'),
password: z.string().min(8, '密碼長度至少需要 8 碼') ,
age: z.number().nullable().optional(),
});
const user = {
password: "12345678",
age: 30
};
UserSchema.parse(user);
} catch (error) {
// 需要確認是 ZodError 物件
if (error instanceof z.ZodError) {
console.log('error.issues', error.issues);
}
}
如果不想要使用 try/catch 方式實作,Zod 也提供透過 safeParse
的方式 return 一個驗證結果物件(plain result object),可以透過 .error
存取這個物件:
const UserSchema = z.object({
name: z.string().min(1, '使用者姓名為必填'),
password: z.string().min(8, '密碼長度至少需要 8 碼') ,
age: z.number().nullable().optional(),
});
const user = {
password: "12345678",
age: 30
};
const validationResult = UserSchema.safeParse(user);
if (validationResult.sucess) {
console.log('驗證通過', validationResult.data);
} else {
console.log('驗證失敗', validationResult.error);
}
4. 型別推導(Inferring types)
Zod 提供了 z.infer<>
utility,可以透過它提取資料型別(extract the inferred type)
==意思是當你定義好了 schema,你同時也定義好了它的type,大幅降低重複的型別定義。==
讓我們修改前面的程式碼:
const UserSchema = z.object({
name: z.string().min(1, '使用者姓名為必填'),
password: z.string().min(8, '密碼長度至少需要 8 碼') ,
age: z.number().nullable().optional(),
});
// 自動提取 Zod Object 的 UserSchema 資料型別
type User = z.infer<typeof UserSchema>;
const user = {
password: "12345678",
age: 30
};
const validationResult = UserSchema.safeParse(user);
if (validationResult.sucess) {
console.log('驗證通過', validationResult.data);
} else {
console.log('驗證失敗', validationResult.error);
}
有時候,input 與 output 的型別不總是相同,以文件中提到的例子為例:
const mySchema = z.string().transform((val) => val.length);
type MySchemaIn = z.input<typeof mySchema>;
// => string
type MySchemaOut = z.output<typeof mySchema>; // equivalent to z.infer<typeof mySchema>
// number
input 要求為 string 型別,但是 output 則要求是 number 型別。 這邊使用到關鍵語法 .transform
做到將輸入為 string 型別的值,轉為 number 型別的值。

Demos
我喜歡在學習某個工具時,同時也透過範例來驗證目前的理解對不對,所以這邊提供了前端、後端的 Demo Projects 提供大家參考。
前端 Demo
前往 Demo Project 👉👉👉👉👉

