Zodを使ってJSONからフォームバリデーションスキーマを構築する

JSONフォームデータ構造をメール、パスワード、長さ、カスタムリファインメントのバリデーションルール付きZodスキーマに変換する方法を学びます。

Advanced

詳細な説明

Zodによるフォームバリデーション

ZodはバリデーションロジックとTypeScript型の両方を単一のスキーマ定義から提供するため、フォームバリデーションに優れています。

フォームJSON例

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "secret123",
  "confirmPassword": "secret123",
  "age": 25,
  "website": "https://johndoe.dev",
  "acceptTerms": true
}

Zodバリデーションスキーマ

import { z } from "zod";

const registrationSchema = z.object({
  name: z.string()
    .min(1, "名前は必須です")
    .max(100, "名前は100文字以内にしてください"),
  email: z.string()
    .email("有効なメールアドレスを入力してください"),
  password: z.string()
    .min(8, "パスワードは8文字以上必要です")
    .regex(/[A-Z]/, "大文字を含む必要があります")
    .regex(/[0-9]/, "数字を含む必要があります"),
  confirmPassword: z.string(),
  age: z.number()
    .int()
    .min(13, "13歳以上である必要があります")
    .max(120),
  website: z.string()
    .url("有効なURLを入力してください")
    .optional(),
  acceptTerms: z.literal(true, {
    errorMap: () => ({ message: "利用規約に同意する必要があります" }),
  }),
}).refine((data) => data.password === data.confirmPassword, {
  message: "パスワードが一致しません",
  path: ["confirmPassword"],
});

type RegistrationForm = z.infer<typeof registrationSchema>;

.refine()によるクロスフィールドバリデーション

.refine()メソッドは複数のフィールドに依存するバリデーションを可能にします:

const dateRangeSchema = z.object({
  startDate: z.string().date(),
  endDate: z.string().date(),
}).refine((data) => data.endDate >= data.startDate, {
  message: "終了日は開始日以降である必要があります",
  path: ["endDate"],
});

React Hook Formとの統合

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";

function RegistrationForm() {
  const form = useForm<RegistrationForm>({
    resolver: zodResolver(registrationSchema),
  });
  // ランタイムバリデーション付きの型安全なフォーム処理
}

複雑なロジック用のSuperRefine

const schema = z.object({
  type: z.enum(["personal", "business"]),
  companyName: z.string().optional(),
}).superRefine((data, ctx) => {
  if (data.type === "business" && !data.companyName) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "ビジネスアカウントには会社名が必要です",
      path: ["companyName"],
    });
  }
});

この宣言的アプローチにより、散在するif-elseバリデーションロジックが排除され、すべてのルールが一箇所に集約されます。

ユースケース

React Hook Formで複数ステップの登録フォームを構築し、すべてのフィールドを検証し、パスワード確認などのクロスフィールドチェックを処理し、型安全なフォーム状態を提供する単一のZodスキーマが必要な場合に使用します。

試してみる — JSON to Zod Schema

フルツールを開く