Zod でバリデーションを行う際、schema.parse(data) と schema.safeParse(data) の違いについて正しい説明はどれか。
解説
parse と safeParse の最大の違いはエラーの扱い方です。parse はバリデーション失敗時に ZodError という例外をスローします。一方 safeParse は例外を投げず、{ success: true, data: T } または { success: false, error: ZodError } という判別可能なオブジェクトを返します。選択肢Aは「parse が boolean を返す」としていますが、parse は成功時にパース済みの値そのものを返すため誤りです。選択肢Cの「非同期専用」も誤りで、非同期バリデーションには parseAsync / safeParseAsync という別のメソッドが用意されています。選択肢Dのエラーメッセージ翻訳機能は safeParse の役割ではありません。try-catch と safeParse、どちらを使うべきかparse を使う場合は try-catch で ZodError を捕捉する必要があります:try { const user = userSchema.parse(input); } catch (e) { if (e instanceof z.ZodError) { console.log(e.issues); } }一方 safeParse ならフロー制御に例外を使わずに済みます:const result = userSchema.safeParse(input); if (!result.success) { console.log(result.error.issues); } else { console.log(result.data); // 型が付いている }実務ではユーザー入力やAPIレスポンスなど「失敗が日常的に起こるデータ」には safeParse、環境変数の読み込みなど「失敗したらアプリを起動すべきでない場面」には parse を使い分けるのが一般的です。例外はあくまで「例外的な事態」に使うという設計原則に沿った判断です。safeParse の戻り値と TypeScript の型の絞り込みsafeParse が返すオブジェクトは判別共用体(Discriminated Union)として型定義されています。そのため result.success を if で分岐すると、true のブロック内では result.data にスキーマから推論された型が自動的に付き、false のブロック内では result.error に ZodError 型が付きます。TypeScript の型の絞り込み(narrowing)がそのまま効くため、型キャストなしで安全にデータを取り扱えます。この仕組みは Zod が TypeScript ファーストで設計されていることの好例です。エラーメッセージをカスタマイズするにはZod のエラーメッセージは各スキーマメソッドの引数で個別に変更できます:const nameSchema = z.string().min(1, '名前は必須です');より高度なケースでは errorMap オプションを使ってプロジェクト全体のメッセージを一括で制御することも可能です。i18n 対応やフォームバリデーションで統一的なメッセージを出したい場合に活用されます。