Mima Design MemottoWEB DESIGNER · mima

ReactとTypeScriptで作る堅牢なフォームバリデーション

Webアプリケーションにおいて、ユーザーが入力するフォームはサービス体験の入り口です。誤ったデータや不完全な情報は、そのままサーバーへ送信されると後工程の処理やデータベースの整合性に深刻な影響を及ぼします。特に業務システムでは、入力チェックを疎かにすると運用コストが増大し、信頼を損なう要因にもなりかねません。

ReactとTypeScriptを組み合わせると、型システムによる恩恵を受けながらコンポーネントベースでフォームを構築できます。型定義により不正な値を早期に検知でき、IDEの補完も強力に効くため、開発体験そのものが向上します。本記事では、その恩恵を最大化するための実践的な手法を紹介します。

フォームバリデーションが担う役割

単なる送信前のチェックではなく、UX全体を左右する重要な要素です。ユーザーが離脱する大きな要因として「分かりにくいエラー」「リアルタイム性のなさ」が挙げられます。たとえばPhoneGapとMonacaでの知見で触れられているように、ハイブリッドアプリでもブラウザと同じようにフォームを扱う場面が増えており、入力検証の品質がアプリ全体の評価に直結します。

サーバー側でもバリデーションは不可欠ですが、クライアント側で先に弾くことで通信量を抑え、応答性を高められます。TypeScriptを導入すると、APIレスポンスの型とフォームの型を揃える設計がしやすくなり、エラーの混入経路を根本から断つ効果が期待できます。

型で縛る入力フィールドの設計

TypeScriptの真価は、フォームデータの型定義にあります。interface FormValues { email: string; password: string; age?: number } のような定義を置くことで、必須項目や任意の項目をコード上で明示できます。Partial<T> や Required<T> を使えば、状態に応じて緩急をつけられます。

入力変更時のハンドラでは、ChangeEvent<HTMLInputElement> の型を活用し、想定外の値が入った時点でコンパイルエラーが走る状態を目指しましょう。これにより、ユニットテストに頼らずとも不具合の大部分を事前に排除できます。

ライブラリの選び方と比較

React向けのフォームライブラリは複数存在し、それぞれ特性が異なります。選定を誤ると、後から別ライブラリへの移行コストが膨らむため、要件との適合性を慎重に見極める必要があります。

ライブラリ 学習コスト 型サポート パフォーマンス バンドルサイズ
React Hook Form 低 優秀 高速 小
Formik 中 良好 標準 中
Zod (Resolver利用) 中 最高 高速 小
Yup 中 良好 標準 中
自作 (useState) 低 自由 用途次第 最小

私のおすすめは、React Hook FormとZodの組み合わせです。型推論が強くスキーマから型を自動生成できるため、type FormInput = z.infer<typeof schema> のように一発でフォームデータの型を取り出せます。

カスタムバリデーションの実装パターン

標準ルールではカバーしきれないケースは多く存在します。郵便番号と住所の整合性、パスワードの強度、複雑な業務ルールなどは、自分でバリデーション関数を用意する必要があります。

const validatePassword = (value: string): true | string => {
  if (value.length < 8) return '8文字以上で入力してください';
  if (!/[A-Z]/.test(value)) return '大文字を含めてください';
  if (!/[0-9]/.test(value)) return '数字を含めてください';
  return true;
};

真偽値ではなくエラーメッセージを返すことで、UI側での表示が楽になります。React Hook FormではsetErrorを使ってサーバーエラーを注入できるため、APIレスポンスのエラー処理も同じ流れで実装可能です。

エラー表示とユーザー体験

エラーメッセージは、否定的・威圧的な表現ではなく、次に何をすべきかを提示する形が理想です。「入力してください」よりも、「メールアドレスを example@example.com の形式で入力してください」のように具体例を添えると、ユーザーは直感的に修正できます。

スマートフォンアプリでは、画面遷移やアニメーションがUXを大きく変えます。スマホアプリのUIアニメーションで紹介されているような工夫をフォームのエラー表示にも応用すると、入力体験全体の質が一段上がります。エラー時にフィールドを軽く揺らす、赤色へ滑らかに変化させるなどの細かい配慮も効果的です。

テストと将来の拡張性

バリデーションロジックはテストが最も書きやすい領域の一つです。境界値、最大長、特殊文字、全半角混在など、実際に入力されうるパターンを想定してユニットテストを用意しましょう。Zodのようなスキーマライブラリを使うと、schema.safeParse(input) で正常系・異常系を統一的にテストできます。

また、ライブラリの選定ドキュメントや設計資料はチームで共有しておくことが重要です。Web制作で読まれるテキストの設計手法に関する記事のように、設計意図を言語化する癖をつけると、後から参加したメンバーもスムーズに保守に関われます。

実践で押さえたいポイント

  • 型定義から先に書き、フォーム全体の構造を可視化してから実装に入る
  • ライブラリ選定時は型推論の強度とコミュニティの活発さを基準にする
  • クライアント側とサーバー側で同じスキーマを共有し、二重実装を避ける
  • エラーメッセージは具体例を示し、次のアクションを明示する
  • 特殊文字や絵文字、長文入力など、エッジケースを意識したテストを用意する
  • アクセシビリティ属性(aria-invalidなど)を適切に付与する
  • フォームの状態管理をコンポーネントから切り出し、再利用可能なHooksにまとめる

ここまで紹介した内容を組み合わせれば、堅牢でユーザビリティの高いフォームを短期間で構築できます。まずは自分のプロジェクトで小さなフォームから試し、徐々に対象範囲を広げてみてください。ReactとTypeScriptの組み合わせは、フォームバリデーションだけでなく、Web開発全体の品質を底上げする強力な武器になります。当ブログでは、こうした開発知見やイベント参加レポートも発信しているので、ぜひ他の記事ものぞいてみてください。