Zodとバリデーション/TypeScriptの基礎

Zod はバリデーションライブラリで入力フォームを通してユーザが入力する値が適切な値かどうかチェックするためのバリデーターとして利用することができます。入力フォームだけではなくバックエンドや localStorage から取得したデータが適切な値なのかチェックするために利用することもできます。つまり何かしら外部から取得したデータをアプリケーション内に取り込む際のバリデーションとして利用することができます。さらに Zod はバリデーションだけではなく TypeScript の型定義を利用する際に利用することもできます。
本文書では React を利用したフォームバリデーションとして Zod をどのように利用することができるのかを確認した後に TypeScript での型の作成方法について説明して Next.js を利用してバックエンドから取得したデータのチェックに Zod を利用して動作確認を行います。最後まで読み終える頃には Zod はフォームのバリデーションに利用するだけではなく受け取ったデータのチェックであればさまざなな場所で活用できることが理解できるようになります。
Zod は React のフォームライブラリの React Hook Form、Vue.js の VeeValidate で利用することもできます。どのようなフォームライブラリで利用できるかはZod Documentationで確認することができます。
React Hook Form での Zod の利用方法については下記の記事で公開しています。
zodはtRPCでも利用することができます。tRPCとは何か?またzodをどこで利用しているのか気になるはぜひ参考にしてみてください。
React でのフォームバリデーション
Zod にあまり馴染みがない人でも最初に Zod の名前を目にするのはフォームバリデーションでの利用だと思います。ここでは React の入力フォームを利用して Zod の動作確認を行うため React のプロジェクト、入力フォームの作成を行い、その後に Zod を利用してバリデーションの設定を行います。
プロジェクトの作成
create-react-app コマンドを利用して React のプロジェクトを作成します。ここでは react-zod-learn というプロジェクト名をつけていますが任意の名前をつけてください。
プロジェクトの作成後にreact-zod-learnに移動してください。
フォームの作成
src フォルダにある App.js ファイルに Email とパスワードの入力項目を持つログインフォームのコードを記述します。
App.jsファイルを更新後にnpm startコマンドを実行してlocalhost:3000にブラウザからアクセスすると以下のログインフォームが表示されます。

Email, パスワードを入力してログインボタンをクリックするとuseStateで定義したdataの内容がブラウザのデベロッパーツールのコンソールに表示されます。
バリデーションによる入力値のチェックを行っていないため入力フォームに何も入れない場合でもメールアドレスの形式に合っていない値を入力してもログインボタンをクリックするとdataの内容が表示されます。
Zodによるバリデーション
Zodのインストール
Zodを利用してバリデーションを行うためにはZodライブラリのインストールが必要になります。
バリデーションの設定
emailには必ず文字列の値を入力する必要がある場合にはZodを利用してスキーマを下記のように定義することでバリデーションを行うことができます。
zodからimportしたzを利用してスキーマを定義しています。string()で文字列であること、min(1)で1文字以上であることを宣言しています。
値のバリデーションによるチェックを定義したmySchemaのparseメソッドを利用し、引数には入力した値が入っているdata.emailを設定しています。
設定後、入力フォームの email に何かの値を入力してログインボタンをクリックするとバリデーションをパスして data の内容がコンソールに表示されます。しかし、email に何も入力せずにログインボタンをクリックするとバリデーションに失敗してコンソールには以下のメッセージが表示されます。
エラーがthrowされるためconsole.logの処理は実行されません。
parse と safeParse
parse メソッドを利用した場合バリデーションに失敗するとエラーが throw されることがわかりました。バリデーションに成功した場合には parse メソッドの結果どのような値が戻されるか確認します。
バリデーションにパスした場合には入力した data.email の値が戻り値に含まれることがわかります。フォームでメールアドレス(email) にjohn@example.comを入力した場合です。
バリデーションを行う方法には parse メソッドの他に safeParse メソッドがあります。parse メソッドから safeParse メソッドに変更することでどのような違いがあるか確認します。引数は parse と同じ入力した値を設定しますが戻り値が異なります。
emailに値を入力した場合にはsafeParseから戻される値はオブジェクトとなりsuccessプロパティが含まれます。
email に値を入力しない場合 parse メソッドではエラーが throw されましたが safeParse メソッドは success プロパティの値が false となり、error プロパティにエラーの情報が表示されます。
safeParseメソッドを利用した場合はsuccessの値を利用してバリデーションにパスしたかどうかのチェックを行うことができます。
オブジェクトスキーマの作成
先ほどは email の入力値のみバリデーションを行いましたが入力フォームでは複数の入力値をチェックする必要があります。その場合にはオブジェクトスキーマを利用することができます。email にはメールアドレスの形式かどうかチェックが行える email()を設定しています。パスワードには文字列が 8 文字以上 32 文字以下であるかチェックを行えると min()と max()を設定しています。
parseメソッドではdataオブジェクトを引数に設定します。
入力フォームに何も入力せず”ログイン”ボタンをクリックするとparseメソッドによりエラーがthrowされます。
エラーメッセージの表示
parseメソッドによってバリデーションを行うことができますがブラウザ上にはエラーが表示されないためユーザにはどのようなエラーが発生しているのかがわかりません。入力値に問題があることをユーザに通知するためエラーの内容をブラウザ上に表示させます。
try, catchを利用してエラーの内容をコンソールに表示させます。throwされたエラーをflattenメソッドで取り出すことができます。
flattenメソッドなどのZodでのエラーのハンドリングについてはhttps://github.com/colinhacks/zod/blob/master/ERROR_HANDLING.mdに記載されています。
flattenメソッドを利用することでえらーの内容はfieldErrorsプロパティに含まれていることがわかります。

新たにuseStateでerrorsを定義してthrowされたエラーの内容を保存します。
保存したerrorsの内容をブラウザ上に表示できるように設定を行います。
設定後はブラウザ上にバリデーションのエラーが表示されるようになります。

ZodでthrowされるエラーはZodErrorオブジェクトのインスタンスかチェックを行いZodErrorオブジェクトのインスタンスの場合のみエラー設定を行います。
エラーメッセージのカスタマイズ
デフォルトのエラーメッセージは英語なので日本語に変更することもできます。
設定後にエラーメッセージを確認すると設定したメッセージになっていることが確認できます。

safeParseによるエラーの設定
parse メソッドの場合はエラーが throw されるので try, catch を利用してエラーを取得しました。safeParse の場合は safeParse メソッドの戻り値に success プロパティが含まれることを確認したので success プロパティの値を分岐に利用することでエラーを設定することができます。
TypeScriptの環境構築
Viteを利用してTypeScriptを利用できる環境を構築します。Project nameには任意の名前をつけてください。frameworkでは”Vanilla”を選択し、variantでは”TypeScript”を選択します。
vite-zod-typescriptフォルダが作成されるので作成されるフォルダに移動してnpm installコマンドを実行します。
npm installコマンド完了後はnpm run devコマンドを実行して開発サーバを起動します。開発サーバ起動はブラウザのデベロッパーツールのコンソールを開きます。
Zodのインストール
Typescript環境でZodを利用するためにはZodライブラリのインストールが必要となります。
srcフォルダにあるmain.tsファイルを更新することでZodの動作確認を行なっていきます。
TypeScriptでのZodの利用
parseメソッドの実行
バリデーションの説明で Zod の parse メソッドの利用方法を理解できていると思うので main.ts ファイルを利用して Zod の parse メソッドを実行します。オブジェクトスキーマを定義しています。
npm run devコマンドを実行している場合はファイルの更新を行うと自動で反映されコンソールにresultの値が表示されます。parseメソッドでは引数に設定したusernameプロパティの値が文字列の”John”なのでバリデーションをパスするのでparseメソッドで指定したオブジェクトが表示されます。
usernameの値を数値にするとバリデーションに失敗しエラーがthrowされます。
コンソールを確認するとZodErrorのメッセージが表示されます。
TypeScriptの型を作成
TypeScriptではinterfaceかtypeを利用してオブジェクトの型を以下のように設定することができます。
Zodでは定義したオブジェクトスキーマを利用してTypeScriptのTypeを作成することができます。
type Userにカーソルを合わせるとUserの型が表示されます。

このようにZodで定義したスキーマを利用することでTypeScriptの型を作成することができます。
Next.js で Zod を利用してみよう
フォームバリデーション以外に Zod はどのような場所で利用することができるか Next.js を利用して確認していきます。
Next.js のプロジェクトの作成と Zod のインストールを行います。
任意の名前でプロジェクトを作成後に Zod のインストールを行います。
バックエンドから戻されるデータでの利用
外部リソースから取得したデータが正しい形式のデータであるのかチェックを行うために Zod を利用することができます。Next.js では Route Handler を利用することができるので Router Handler を外部のリソースとして利用します。
src/app ディレクトリの下に app ディレクトリを作成して route.ts ファイルを作成して以下のコードを記述します。
components ディレクトリを作成して User.tsx ファイルを作成して User コンポーネントの中で http://localhost:3000/api にアクセスします。
components/User.tsx
作成した User コンポーネントは app ディレクトの page.tsx ファイルで import します。
ブラウザで確認するとコンソールには”John”が表示されます。 何かの拍子に route.ts 側で設定した firstName が firstname に変更されたとします。
ブラウザのコンソールには”undefined”が表示されます。もしこの時に Zod によりバリデーションを行っていたらどのようになるか確認します。スキーマの定義を行います。
定義した UserSchema を利用して parse を実行します。
ブラウザ側でアクセスすると先ほどまでは undefined と表示されましたが parse でエラーが発生すると Exception が throw されるので画面にエラーメッセージが表示されます。
route.ts の firstname を firstName に変更するか UserSchema 側で firstName を fristname にするとエラーは解消します。
下記のように戻される値が数値ではなく文字列だった場合の動作確認も行います。
ブラウザ上には下記のエラーが表示されます。
zod を利用していない場合では UsetType で id の型を number にしていても特にエラーは表示されずバックエンドから戻された id が文字列として表示されます。
このように外部リソースから取得したデータが正しい形式のデータかどうかを Zod を利用してチェックすることができます。
フォームのバリデーションという狭い範囲に限らずデータを取得する場所ならどこでも利用できることがわかったかと思います。ぜひさまざまな場所で Zod を利用してみてください。