でじぼうです。
TypeScriptのフォーム実装でよく登場する、Zod
のバリデーション記述についてまとめました。

でじぼう
この記事は下記の方がおすすめ!
- Zodってなに?
- バリデーションはどんな種類があるの?
- バリデーション実行はどのタイミング?
Zodとは?

Zod(ゾッド)は、TypeScript向けのスキーマバリデーションライブラリです。
簡単に言うと、「このデータはこの形であるべき!」というルールをコードで定義し、そのルール通りになっているかチェックする仕組みです。
特に、ReactやNext.jsなどのフレームワークと組み合わせて使われるReact Hook Formと相性が良く、フロントエンドのフォームバリデーションでよく利用されます。
よく使うバリデーション一覧
下記に、よく利用するZod
のバリデーション一覧をまとめました。
チェック内容 | Zod記述 | エラーメッセージ |
---|---|---|
未入力(必須) | z.string().min(1, “名前を入力してください”) | 名前を入力してください |
文字数の最小制限 | z.string().min(3, “3文字以上で入力してください”) | 3文字以上で入力してください |
文字数の最大制限 | z.string().max(20, “20文字以内で入力してください”) | 20文字以内で入力してください |
メール形式 | z.string().email(“正しいメールアドレスを入力してください”) | 正しいメールアドレスを入力してください |
正規表現チェック | z.string().regex(/^\d+$/, “数字のみで入力してください”) | 数字のみで入力してください |
特定の文字列のみ許可 | z.enum([“男”, “女”, “未回答”]) | 性別を選択してください |
数値の範囲 | z.number().min(1, “1以上の数値を入力してください”) | 1以上の数値を入力してください |
真偽値のチェック | z.boolean().refine(val => val, “同意が必要です”) | 同意が必要です |
日付の存在確認 | z.date({ required_error: “日付を選択してください” }) | 日付を選択してください |
nullを許容 | z.string().nullable() | ※nullもOKな項目に使用 |
オプショナル | z.string().optional() | ※未入力(undefined)もOK |
modeの違いとタイミング解説(React Hook Form向け)
React Hook Formでは、いつバリデーションを実行するかを mode
で指定できます。
mode設定値 | タイミングの説明 | 用途例 |
---|---|---|
onSubmit | フォーム送信時のみ実行 | エラー表示を最小限にしたい時 |
onChange | 入力のたびに(1文字でも入力すると即時) | 即時エラー表示が必要な時 |
onBlur | フォーカスが外れたときに実行 | 入力中は集中させたい時 |
onTouched | 一度触れてからフォーカスが外れたときに実行 | 初回は控えめ・2回目以降に即バリデーション |
all | onChange+onBlur+onSubmitすべて実行 | 厳格なバリデーションが必要な場合 |
下記は、mode: onChange
を指定した場合
const {
register, // 各フォーム要素にバリデーションを適用するための関数
handleSubmit, // フォーム送信時の処理をまとめる関数
formState: { errors } // バリデーションエラーの状態を管理するオブジェクト
} = useForm({
mode: "onChange" // 入力が変わるたびにバリデーションを実行する
});
下記は、mode を省略した場合。デフォルトの onSubmit
に設定される
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
実装コード
Zodを使用したバリデーションチェックの実装例をご紹介します。
使用している技術
言語:TypeScript
React
:UIフレームワークReact Hook Form
:フォーム処理ライブラリZod
:バリデーションスキーマライブラリ- zodResolver:ZodとReact Hook Formを接続
実装内容
名前・メールアドレス・電話番号の入力フォームを作成
入力のたびにバリデーションが実行され、間違っていれば即エラーメッセージを表示
- 未入力チェック(全項目)
- メールアドレス形式のチェック
- 電話番号が数字やハイフンのみかを正規表現でチェック
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
// 入力項目のバリデーションルール
const schema = z.object({
name: z.string().min(1, "名前を入力してください"),
email: z
.string()
.min(1, "メールアドレスを入力してください")
.email("正しいメールアドレス形式で入力してください"),
tel: z
.string()
.min(1, "電話番号を入力してください")
.regex(/^[0-9\-]+$/, "数字またはハイフンのみで入力してください"),
});
// Zodスキーマからフォームの型を自動生成
type FormData = z.infer<typeof schema>;
export default function ContactForm() {
// useFormでフォームを初期化
const {
register, // 各inputにバリデーションを紐づける
handleSubmit, // フォーム送信時にバリデーションを実行
formState: { errors }, // 各項目のバリデーションエラー情報
} = useForm<FormData>({
resolver: zodResolver(schema), // Zodで定義したスキーマを使う
mode: "onChange", // 入力ごとにバリデーション実行
});
// バリデーション成功時の処理
const onSubmit = (data: FormData) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} placeholder="名前" /> // registerの記載でチェック対象とする
{errors.name && <p>{errors.name.message}</p>} // エラーメッセージの表示
<input {...register("email")} placeholder="メールアドレス" />
{errors.email && <p>{errors.email.message}</p>}
<input {...register("tel")} placeholder="電話番号" />
{errors.tel && <p>{errors.tel.message}</p>}
<button type="submit">送信</button>
</form>
);
}
よくあるミスや注意点
min(1)
だけだと空白(スペース)だけの入力を許してしまう
→.refine(val => val.trim() !== '')
を追加すると◎null
を許容したい場合は.nullable()
を使う
→ 例:z.string().nullable()
これはnull
を受け入れ、未入力とは別の扱いになります。zodResolver
を使わないとReact Hook Formとの連携ができないので注意
コメント