概要
入力を信じるな、検証せよ。
ユーザーの入力、外部APIのレスポンス、ストレージからの復元――これら**“信用ならない値”**に対して、
何を必須とし、どの形式を受け入れ、どう誤りを検出・通知するかが、アプリケーションの安全性とUXを左右する。
本稿では、バリデーションを次の観点から整理する:
- 型検査・null/undefinedの検出
- 複数条件を持つフィールド検証
- 同期/非同期バリデーション
- UI表示との責務分離
- 汎用的なバリデーション構造の構築
1. 型チェックと存在確認
✅ 単純なプリミティブチェック
function isString(value) {
return typeof value === 'string';
}
function isNonEmptyString(value) {
return isString(value) && value.trim().length > 0;
}
→ ✅ typeof
/ Array.isArray()
/ instanceof
による型ガードを基本とする
2. 必須チェックと複数条件の設計
function validateEmail(value) {
if (!value) return 'メールアドレスは必須です';
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return '形式が正しくありません';
return null;
}
→ ✅ nullなら成功 / エラーメッセージを返す方式が実用的
3. フィールド単位のバリデータ関数群
const validators = {
name: (v) => v?.trim() ? null : '名前は必須です',
age: (v) => v > 0 ? null : '年齢は1以上を入力してください',
email: validateEmail
};
→ ✅ 各フィールドに責任を持たせ、ルールを分離
→ ✅ フォーム設計において再利用可能
4. フォーム全体の検証戦略
function validateForm(data) {
const errors = {};
for (const key in validators) {
const error = validators[key](data[key]);
if (error) errors[key] = error;
}
return Object.keys(errors).length > 0 ? errors : null;
}
- ✅ エラーがあるかどうかは
null
またはerrors
の有無で判定 - ✅ フロントエンドでの事前検証 → API送信 → サーバー検証の流れに統合可能
5. 非同期バリデーション(重複チェックなど)
async function checkUsernameExists(username) {
const res = await fetch(`/api/check-username?name=${username}`);
const { exists } = await res.json();
return exists ? 'このユーザー名はすでに使われています' : null;
}
- ✅ 入力中でも検証可能に(例:Debounce + 非同期検証)
- ✅ UI側で非同期の状態管理が必要(
isChecking
フラグなど)
6. UIとバリデーションの責務分離
- ✅
validateXXX()
関数は純粋関数とする(DOM操作しない) - ✅ 表示(例:赤枠・メッセージ)はコンポーネント側が担当
- ✅ バリデーション関数はテスト可能なロジックに留める
7. 汎用バリデーションユーティリティの構築
function createValidator(rules) {
return (value) => {
for (const rule of rules) {
const error = rule(value);
if (error) return error;
}
return null;
};
}
// 使用例
const validatePassword = createValidator([
(v) => v.length >= 8 ? null : '8文字以上必要です',
(v) => /[A-Z]/.test(v) ? null : '大文字を含めてください'
]);
→ ✅ チェックルールを配列で柔軟に組み合わせ可能
→ ✅ 共通ルールの再利用が容易に
設計判断フロー
① 値の型が保証されない? → 型ガード関数を定義
② 必須項目? → 空チェック + 明示的なエラーメッセージ
③ ルールが複数ある? → 順序付きの関数配列で検証
④ APIと連携したい? → 非同期検証関数を導入
⑤ UI更新と検証を分離したい? → 検証は純粋関数として定義
よくあるミスと対策
❌ バリデーション関数内でDOMを直接操作
→ ✅ 検証は検証、表示は表示。役割を分ける
❌ エラー表現がコード内にハードコーディングされすぎる
→ ✅ 国際化や再利用性を考慮し、メッセージ辞書化を検討
❌ 同期/非同期検証が混在して管理不能に
→ ✅ ステータスを分離(例:同期検証結果 + 非同期検証中フラグ)
結語
バリデーションとは“値の正しさ”ではなく、**“正しさの判断基準を構造として設計する行為”**である。
- チェックは明確に
- メッセージは意味を持って
- 責務は関数に封じて
- 検証は構造で繰り返せるように
ユーザーの安心は、信頼できる入力から生まれる。
堅牢な検証は、UIの品位と信頼性を支える基盤である。