🔍

Zod 4、いつの間に完成していたの!?

に公開

今月 10 日ごろ、私のアンテナに捕捉されることなく Zod の v4 がリリースされました。この記事では、v4 で追加・変更された内容のうち、私 (🔰) が特に注目した機能をご紹介します!

1.【New!】国際化

v4 から、Zod は日本語を含む複数のロケールに対応したエラーメッセージを提供するようになりました 🎉

import * as z from "zod";

z.config(z.locales.ja());

例えば、以下のような日本語のエラーメッセージが表示できます。ただし残念ながら、型名などは英語のままです。

  • 無効なメールアドレス
  • 小さすぎる値: arrayは1要素以上である必要があります
  • 大きすぎる値: stringは50文字以下である必要があります

Zod にブラウザーの言語設定に応じた設定をする API はありませんが、以下のように工夫することで実現できます。

// ブラウザーの言語設定に基づいてロケールを設定
const locale = navigator.languages
  .map((lang) => lang.replaceAll("-", "") as keyof typeof z.locales)
  .find((lang) => z.locales[lang]);
z.config(locale && z.locales[locale]() || z.locales.en());

ただし、カスタマイズしたエラー メッセージをロケールごとに用意するための API はありません。現時点では「internationalization (国際化)」というより「localization (地域化)」機能という感じです。

今後の拡張に期待しています。

2.【Changed!】email 仕様の明文化

v4 では z.email() でのバリデーション仕様が明記されました。おおよそ Gmail で使われているものと同じなのだそうです。

https://zod.dev/api#emails

ちなみに、メール アドレスにはさまざまな形式があることをご存知でしょうか?

📚 Wikipedia: Valid email addresses

実は私は大文字混じりのアドレスを持っています。メール サーバーは given.family@example.com 宛のものも私に届けてくれるとはいえ、"Given.Family"@example.com のような普通じゃないアドレスもサポートしたい場合には、正規表現を指定できます。

z.email({ pattern: z.regexes.rfc5322Email });

3.【New!】ファイル スキーマ

ファイルを送信する際に、MIME タイプやサイズでバリデーションできるようになりました。

z.file()
  .mime(["image/png", "image/jpeg", "image/gif", "image/svg+xml", "image/webp"]) // 画像
  .min(1_000_000)  // 1 MB 以上
  .max(10_000_000) // 10 MB 以下

shadcn/ui + React Hook Form で以下のように使用することができます。(なぜか <Input type="file" {...field} /> ではダメでした。)

<FormField
  control={form.control}
  name="photo"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Photo</FormLabel>
      <FormControl>
        <Input
          type="file"
          onChange={(e) => {
            const file = e.target.files?.[0];
            field.onChange(file);
            if (file) {
              field.onBlur();
            }
          }}
          name={field.name}
          ref={field.ref}
        />
      </FormControl>
      <FormDescription>
        Upload a photo (1MB - 10MB).
      </FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>

サーバー側でバリデーションすると、スマホの回線で巨大ファイルの送信を待ってから「大きすぎます」とエラーが返るという残念なことになりますが、これからはクライアント サイドで簡単に判定できますね。

4.【New!】JSON Schema への変換

Zod のスキーマから JSON Schema を生成できるようになりました。これは以下のような用途で活躍しそうです。

  • バックエンドが別言語の場合、共通のスキーマとして利用
  • API 仕様の自動生成
  • VS Code 上での補完や型チェック
const formJsonSchema = z.toJSONSchema(formSchema);

5.【New!】再帰的な構造のオブジェクト

v4 からは、再帰的な構造のオブジェクトのスキーマも定義可能になりました。

以下に公式の例をご紹介します。

const Category = z.object({
  name: z.string(),
  get subcategories(){
    return z.array(Category)
  }
});
 
type Category = z.infer<typeof Category>;
// { name: string; subcategories: Category[] }

https://zod.dev/api#recursive-objects

一般的なバリデーション項目にはないと思いますが、独自の UI でツリーを作るとすればクライアント側のバリデーションは不要だと思いますが、バックエンドも TypeScript (Zod) を使う場合に活用できそうでしょうか?

まとめ

今回ご紹介した注目ポイントはこちら 🙌

  1. 国際化
  2. email 仕様の明文化
  3. ファイル スキーマ
  4. JSON Schema への変換
  5. 再帰的な構造のオブジェクト

今後は新規に Zod を使う時には v4 を使うことになっていくと思います。

既存の実装で v3 を継続利用していて仕様を確認する場合は、公式サイト左上のメニューで Zod 3 を選ぶのをお忘れなく!

他の方の記事紹介

Zod 4 については、ベータ版の頃から日本語記事が執筆されています。素晴らしい記事なので、ぜひ参考にしてください! (投稿日の昇順のつもりです。)

https://qiita.com/zhang_hang/items/4dbc454891d0f0070ca1

https://zenn.dev/codeunit/articles/f99e3546c1574a

https://bufferings.hatenablog.com/entry/2025/05/08/033208

https://zenn.dev/aprender/articles/5bfa30fd37f99c

https://qiita.com/zumi0/items/216b2eb22ab5165d6b2e

Discussion