•10 min read

TypeScriptだけでは不十分:Next.jsでZodを使ったエンドツーエンドの型安全性

TypeScriptだけでは不十分:Next.jsでZodを使ったエンドツーエンドの型安全性
Audio Briefing
0:00 / 0:00

型安全性の幻想

TypeScriptは、現代のJavaScriptアプリケーションの救世主としてしばしば語られます。タイポを検出し、オブジェクトプロパティを自動補完し、開発中の未定義関数の呼び出しを防ぎます。

しかし、厳格なTypeScriptコンパイラ設定を有効にしているにもかかわらず、毎日何百もの本番Next.jsおよびNode.jsアプリケーションが、TypeError: Cannot read properties of undefined (reading 'map')やTypeError: data.slice is not a functionといったエラーでクラッシュしています。

なぜこのようなことが起こるのでしょうか?

それは、TypeScriptがランタイムに存在しないからです。コードがコンパイルされると、すべてのインターフェース、型エイリアス、ジェネリックパラメータ、および型アサーション(as User)はJavaScriptバンドルから消去されます。ネットワーク境界(受信HTTPリクエスト、Next.jsサーバーアクションのペイロード、サードパーティのWebhookイベント、データベースクエリ結果)では、コードを流れるデータは完全に型付けされていません。

真のエンドツーエンドの信頼性を実現するには、システムにデータが入力されるときにデータを検証する必要があります。そこでZodが不可欠になります。

生のAPI JSONをTypeScriptインターフェースとZodスキーマに即座に変換する必要がありますか?当社のコンパニオンツール JSON to TypeScript & Zod Generator Tool をご利用ください。


Advertisement

静的型とランタイムスキーマ

TypeScriptインターフェースとZodスキーマの根本的な違いを理解することが、堅牢なアーキテクチャを構築するための鍵です。

側面TypeScriptインターフェースZodランタイムスキーマ
ライフサイクルステージ
コンパイル時のみ(ビルド中に消去される)
ランタイム実行(すべてのライブリクエスト中にアクティブ)
ネットワーク境界防御
保護なし。データキャスト(例:body as RequestBody)を盲目的に信頼する
完全な防御。実行前に不正なペイロードや悪意のあるインジェクションを拒否する
バンドルサイズ
バンドルに追加されるのは0 kB(純粋な型メタデータ)
わずか約12 kBのランタイムパーサーライブラリ
信頼できる唯一の情報源(Single Source of Truth)
ランタイムバリデーターも記述する場合、手動での同期が必要
z.infer<typeof Schema>を介してTypeScript型を自動的に推論する

脆弱なサーバーアクションをZodにリファクタリングする

開発者がランタイム検証なしに型アサーションを使用する、Next.jsサーバーアクションの一般的な脆弱性を見てみましょう。


Zodの高度な使用法のための4つの強力なテクニック

1. フォームデータとURL検索パラメータのためのz.coerce

HTML FormDataまたはNext.js searchParamsをパースする場合、すべてが文字列として到着します("42"、"true")。手動でparseInt()やBoolean()を記述する代わりに:

const FilterSchema = z.object({
  page: z.coerce.number().default(1),
  limit: z.coerce.number().default(20),
  active: z.coerce.boolean().default(true),
});

2. safeParse vs parse

  • schema.parse(data)は検証に失敗した場合、ZodErrorをスローします。これは、try/catchブロック内、またはグローバルエラーミドルウェアを持つトップレベルのAPIハンドラー内でのみ使用してください。
  • schema.safeParse(data)は決してスローしません。これは判別共用体(discriminated union)を返します:{ success: true, data }または{ success: false, error }。これはNext.jsサーバーアクションやReact Hook Formに最適です。

3. スキーマの構成と継承

Zodスキーマは構成可能です。拡張、マージ、フィールドの選択ができます。

const BaseUserSchema = z.object({
  id: z.string().uuid(),
  createdAt: z.date(),
});

const UpdateProfileSchema = BaseUserSchema.extend({
  bio: z.string().max(500).optional(),
  displayName: z.string().min(2),
});

4. .refine()によるカスタムリファインメント

クロスフィールド検証(例:「確認パスワード」が「パスワード」と一致することを確認する)の場合:

const PasswordChangeSchema = z.object({
  newPassword: z.string().min(8),
  confirmPassword: z.string().min(8),
}).refine((data) => data.newPassword === data.confirmPassword, {
  message: "Passwords do not match",
  path: ["confirmPassword"],
});

Advertisement

インタラクティブクイズ:Zodの知識を試す


こちらもおすすめ

よくある質問

マイクロベンチマークでは、Zodは一般的なJSONペイロードをミリ秒の数分の1(標準オブジェクトで0.1ms未満)で検証します。無視できるCPUコストは、サイレントなデータベース破損や壊滅的なサーバークラッシュを防ぐことで圧倒的に相殺されます。
型を手動で重複させるべきではありません。Zodスキーマを信頼できる唯一の情報源として定義し、z.infer<typeof Schema>を使用して静的TypeScript型を自動的に導出してください。これにより、ランタイム検証とコンパイル時チェックが乖離することがなくなります。
無料のオンラインツール JSON to TypeScript & Zod Generator を使用して、任意のJSONペイロードを貼り付けるだけで、整形されたTypeScriptインターフェースとすぐに使えるZodスキーマをワンクリックで取得できます。
Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement
Next.js Middleware:堅牢な認証と認可の構築
nextjs

Next.js Middleware:堅牢な認証と認可の構築

Next.js App Routerアプリケーションを、joseによるJWTトークン検証、ロールベースルーティング、リダイレクトパイプラインといったEdge Middlewareで保護する方法を学びましょう。

Read more