Zod 入門
Zod とは
Zod は TypeScript / JavaScript 向けのバリデーションライブラリです。
型定義と実行時バリデーションを一つの Zod スキーマで扱える点が特徴です。
Zod が解決する問題
TypeScript は型定義と型チェックを行うことができますが、それは開発時・コンパイル時にしか意味をなしません。
つまりコンパイル後の実行時には型チェックが行われないので、API レスポンスやフォーム入力などの外部入力データの型の信頼性を保証できません。
Zod はこれを解決するために「実行時の型バリデーション」と「Zod スキーマから TypeScript 型を生成する」機能を有しています。
基本的な使い方
スキーマを用いた型安全なバリデーション
import { z } from "zod";
const UserSchema = z.object({
name: z.string(), // string 型
age: z.number().int().positive(), // number型 かつ 正の整数
});
UserSchema.parse({ name: "Alice", age: 20 });
// => { name: "Alice", age: 20 }
UserSchema.parse({ name: "Alice", age: -1 });
// => ZodError
Zod スキーマを元に .parse() を用いてバリデーションを行います。
.parse()は型一致であればその値をそのまま、型不一致であればZodErrorを投げます。
try {
UserSchema.parse(data);
} catch (e) {
console.error("Validation failed", e);
}
このバリデーションを行うことにより型安全なデータのみをアプリ内で扱うことができます。
なお型が異なる場合でもエラーを返したくない場合は .safeParse() を使うことができます。
UserSchema.safeParse({ name: "Alice", age: 20 });
// => { success: true; data: { name: "Alice", age: 20 } }
UserSchema.safeParse({ name: "Alice", age: -1 });
// => { success: false; error: ZodError }
TypeScript の型生成
type User = z.infer<typeof UserSchema>;
const user: User = { name: "Alice", age: 20 };
Zod スキーマから TypeScript の型も得ることができます。
実際の使い方
TypeScript の型と違い、Zod では実行時に型チェックが行われるので、API リクエスト、フォーム入力時、環境変数の取得など、外部からのデータを受け取り、扱う際にメリットが大きいです。
.parse()で型安全が保証された値のみをアプリ内で扱えるため、不正値による実行時エラーの発生を防ぎやすくなります。
実行時の型チェックの他に Zod スキーマから TypeScript 型も生成できるため、スキーマの二重管理になることもありません。
API リクエストのサンプル
import { z } from "zod";
// レスポンスの形を Zod スキーマで定義
const UserSchema = z.object({
id: z.string(),
name: z.string(),
age: z.number().int().positive().optional(),
});
// 型の自動生成
type User = z.infer<typeof UserSchema>;
// API から取得 & レスポンスのバリデーション
async function fetchUser(userId: string): Promise<User> {
const res = await fetch(`https://api.example.com/users/${userId}`);
if (!res.ok) {
throw new Error("API request failed");
}
const json = await res.json(); // ここで型はまだ不明
// ここで実行時バリデーション + 型付け
// 型が正しくない場合は ZodError を投げる
const user = UserSchema.parse(json);
// ここから先は User 型として安全に扱える
return user;
}
例外を投げない API リクエストのサンプル
型が正しくないデータが返された場合でも例外にしたくない場合は、safeParse()を使います。
async function fetchUserSafe(userId: string) {
const res = await fetch(`https://api.example.com/users/${userId}`);
if (!res.ok) throw new Error("API request failed");
const json = await res.json();
const result = UserSchema.safeParse(json); // safeParse()
if (!result.success) {
console.error("Validation error:", result.error);
// null を返す・デフォルト値を返すなど
return null;
}
// ここは result.data が User 型
return result.data;
}
ちなみに API リクエストなら、fetchとバリデーションをしてくれるヘルパーをlib/apiClient.tsとかで配置すると、楽でプロジェクト全体で Zod を使う運用がしやすそうです。
まとめ
Zod は外部からのデータを実行時バリデーションで型安全に扱うことが出来るライブラリでした。
Zod が特に効果を発揮する部分としては以下が考えられます。
- API リクエスト
- フォーム入力
- URL / クエリパラメータの取得
- 環境変数の検証
- Config ファイルの検証
- JSON ファイルの検証
逆に言うと外部からのデータが流れてこない、内部の型だけで済む場合は TypeScript の型だけで十分そうです。
この記事では Zod の概要しか扱いませんでしたが、インストール方法や細かなスキーマの定義、エラー処理については公式ドキュメントが扱っています。
Discussion