でじぼうです。
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との連携ができないので注意

 
  
 

コメント