テーマの整理:「配列バリデーション」とは何か
ここでの「バリデーション」は、配列の中身が「業務で期待している形・値になっているか」をチェックすることです。 特に「オブジェクト配列」(レコード一覧)に対して、
- 必須項目が入っているか
- 型が正しいか(数値・文字列・真偽値など)
- 値の範囲やルールを守っているか
をまとめて確認するためのユーティリティが「配列バリデーション」です。
ポイントは、「1 件ずつ if 文でチェックする」のではなく、“配列全体を、ルールに従って一括で検査する”ことです。
基本コンセプト:「ルールを決めて、配列全体に適用する」
どんなデータをバリデーションするのか
よくある形は、こんなオブジェクト配列です。
const users = [
{ id: 1, name: "Alice", age: 20, email: "alice@example.com" },
{ id: 2, name: "", age: -5, email: "not-an-email" },
];
JavaScriptここから、例えば次のようなルールでチェックしたくなります。
- id は必須で、数値で、1 以上。
- name は必須で、空文字は禁止。
- age は 0 以上 120 以下。
- email は「ざっくりメールっぽい形」かどうか。
この「どうチェックするか」を「バリデーションルール」として定義し、 それを配列全体に適用するのが配列バリデーションです。
ユーティリティ 1:1 レコード分のバリデーション関数を作る
まず「1 件」をどうチェックするかを決める
配列全体をチェックする前に、「1 レコードをどう検査するか」を関数にします。
function validateUser(user) {
const errors = [];
if (user.id == null) {
errors.push("id は必須です");
} else if (typeof user.id !== "number" || user.id <= 0) {
errors.push("id は 1 以上の数値である必要があります");
}
if (!user.name || user.name.trim() === "") {
errors.push("name は空文字ではいけません");
}
if (typeof user.age !== "number" || user.age < 0 || user.age > 120) {
errors.push("age は 0〜120 の数値である必要があります");
}
if (typeof user.email !== "string" || !user.email.includes("@")) {
errors.push("email は @ を含む文字列である必要があります");
}
return errors;
}
JavaScript重要ポイントをかみ砕いて説明
errors は「そのレコードに対するエラーメッセージの配列」です。 id は「null / undefined なら必須エラー」「数値でない・1 以下なら範囲エラー」を出しています。 name は「空文字・空白だけ」を禁止しています。 age は「型が数値か」「範囲が 0〜120 か」をチェックしています。 email は「ざっくり @ を含むかどうか」で簡易チェックしています。
この関数は、「1 ユーザーが正しいかどうか」を判定し、 問題があればその理由を文字列で返します。
ユーティリティ 2:配列全体をバリデーションする
実装:validateUsersArray
1 件分のバリデーション関数を、配列全体に適用します。
function validateUsersArray(users) {
if (!Array.isArray(users)) {
return { valid: false, errors: ["配列ではありません"] };
}
const allErrors = [];
users.forEach((user, index) => {
const errors = validateUser(user);
if (errors.length > 0) {
allErrors.push({
index,
errors,
});
}
});
const valid = allErrors.length === 0;
return { valid, errors: allErrors };
}
JavaScript重要ポイントをかみ砕いて説明
まず「配列かどうか」をチェックし、配列でなければ即エラーにします。 各ユーザーについて validateUser を呼び、エラーがあれば index(何番目の要素か)と一緒に記録します。 最後に「エラーが 0 件なら valid = true」「1 件以上あれば valid = false」と判定します。
戻り値は、
{
valid: true/false,
errors: [
{ index: 1, errors: ["name は空文字ではいけません", "age は 0〜120 の数値である必要があります"] },
...
]
}
JavaScriptのような形になります。 「どの行に」「どんな問題があるか」が分かるので、画面やログに出しやすいです。
例題 1:ユーザー配列をバリデーションして結果を見る
const users = [
{ id: 1, name: "Alice", age: 20, email: "alice@example.com" },
{ id: 2, name: "", age: -5, email: "not-an-email" },
];
const result = validateUsersArray(users);
console.log("valid:", result.valid);
console.log("errors:", JSON.stringify(result.errors, null, 2));
JavaScript出力イメージはこうなります。
valid: false
errors: [
{
"index": 1,
"errors": [
"name は空文字ではいけません",
"age は 0〜120 の数値である必要があります",
"email は @ を含む文字列である必要があります"
]
}
]
ここでのポイントは、
1 件目は問題なし。 2 件目(index 1)に、name・age・email の 3 つの問題がある。
ということが、はっきり分かることです。
ユーティリティ 3:バリデーションルールを「定義オブジェクト」として持つ
シナリオ
ユーザーだけでなく、売上データや商品データなど、複数の種類のレコードがある。 それぞれに「バリデーションルール」を持たせたい。
ルール定義の形を決める
例えば、こんな形で「フィールドごとのルール」を持てます。
const UserValidationRules = {
id: [
(v) => (v == null ? "id は必須です" : null),
(v) =>
typeof v !== "number" || v <= 0
? "id は 1 以上の数値である必要があります"
: null,
],
name: [
(v) =>
!v || v.trim() === ""
? "name は空文字ではいけません"
: null,
],
age: [
(v) =>
typeof v !== "number" || v < 0 || v > 120
? "age は 0〜120 の数値である必要があります"
: null,
],
email: [
(v) =>
typeof v !== "string" || !v.includes("@")
? "email は @ を含む文字列である必要があります"
: null,
],
};
JavaScriptここでのポイントは、
各フィールドに「チェック関数の配列」を割り当てていることです。 チェック関数は「問題があればエラーメッセージを返し、問題なければ null を返す」スタイルにしています。
汎用バリデーション関数:validateRecordWithRules
function validateRecordWithRules(record, rules) {
const errors = [];
for (const key in rules) {
const validators = rules[key];
const value = record[key];
validators.forEach((fn) => {
const message = fn(value, record);
if (message) {
errors.push(`${key}: ${message}`);
}
});
}
return errors;
}
JavaScript使い方はこうです。
function validateUsersArrayWithRules(users) {
if (!Array.isArray(users)) {
return { valid: false, errors: ["配列ではありません"] };
}
const allErrors = [];
users.forEach((user, index) => {
const errors = validateRecordWithRules(user, UserValidationRules);
if (errors.length > 0) {
allErrors.push({ index, errors });
}
});
return { valid: allErrors.length === 0, errors: allErrors };
}
JavaScriptこの形にしておくと、「ルール定義」と「バリデーション処理」がきれいに分離されます。 仕様変更があったときは、UserValidationRules だけを直せばよくなります。
ユーティリティ 4:バリデーション結果を「使いやすく」扱う
シナリオ
画面で「どの行にエラーがあるか」を表示したい。 ログで「エラー行だけ」を出したい。
エラー行だけを抽出する
バリデーション結果から、「エラーのあるレコードだけ」を取り出すこともできます。
function extractInvalidRecords(records, validationResult) {
return validationResult.errors.map((e) => ({
index: e.index,
record: records[e.index],
errors: e.errors,
}));
}
JavaScript使い方はこうです。
const result = validateUsersArray(users);
const invalids = extractInvalidRecords(users, result);
console.log(JSON.stringify(invalids, null, 2));
JavaScriptこれで、
- どの行がダメなのか
- その行の中身は何なのか
- どんなエラーがあるのか
をまとめて確認できます。
配列バリデーションユーティリティで意識してほしい重要ポイント
「バリデーションは“入口でまとめてやる”」という発想
バリデーションは、できるだけ「データが入ってきた入口」でまとめてやるのが基本です。
API 受信直後。 CSV/Excel 読み込み直後。 フォーム送信直後。
ここで配列バリデーションを通しておけば、 後続の処理は「正しいデータだけを前提に書ける」ようになります。
初心者のうちは、
「この処理の前に、バリデーションを一回挟めないか?」
と考える癖をつけると、 コード全体の安定感がかなり変わります。
「何がダメなのか」を人間に伝わる形で返す
バリデーションは、「通るかどうか」だけでなく、 「なぜ通らないのか」を人間に伝えることが大事です。
- どの行か(index)。
- どの項目か(key)。
- 何が問題か(メッセージ)。
これをセットで返すようにしておくと、 画面でもログでも、原因がすぐ分かります。
手を動かして「配列バリデーション」の感覚をつかむ
次のコードを実行して、
- 1 レコードのバリデーション
- 配列全体のバリデーション
- エラー行の抽出
を体感してみてください。
function validateUser(user) {
const errors = [];
if (user.id == null) {
errors.push("id は必須です");
} else if (typeof user.id !== "number" || user.id <= 0) {
errors.push("id は 1 以上の数値である必要があります");
}
if (!user.name || user.name.trim() === "") {
errors.push("name は空文字ではいけません");
}
if (typeof user.age !== "number" || user.age < 0 || user.age > 120) {
errors.push("age は 0〜120 の数値である必要があります");
}
if (typeof user.email !== "string" || !user.email.includes("@")) {
errors.push("email は @ を含む文字列である必要があります");
}
return errors;
}
function validateUsersArray(users) {
if (!Array.isArray(users)) {
return { valid: false, errors: ["配列ではありません"] };
}
const allErrors = [];
users.forEach((user, index) => {
const errors = validateUser(user);
if (errors.length > 0) {
allErrors.push({ index, errors });
}
});
return { valid: allErrors.length === 0, errors: allErrors };
}
function extractInvalidRecords(records, validationResult) {
return validationResult.errors.map((e) => ({
index: e.index,
record: records[e.index],
errors: e.errors,
}));
}
function demo() {
const users = [
{ id: 1, name: "Alice", age: 20, email: "alice@example.com" },
{ id: 2, name: "", age: -5, email: "not-an-email" },
];
const result = validateUsersArray(users);
console.log("valid:", result.valid);
console.log("errors:", JSON.stringify(result.errors, null, 2));
console.log("invalid records:", JSON.stringify(extractInvalidRecords(users, result), null, 2));
}
demo();
JavaScriptまとめ:配列バリデーションユーティリティで「壊れたデータを、入口で止める」
配列バリデーションは、 「壊れた・おかしなデータを、業務ロジックに入る前にきちんと止めるためのユーティリティ」です。
プロジェクトに例えば次のような形で置いておくイメージです。
export function validateRecordWithRules(record, rules) { ... }
export function validateUsersArray(users) { ... }
export const UserValidationRules = { ... };
JavaScriptそして、
API 受信直後、 CSV/Excel 読み込み直後、 フォーム送信直後
など、「データが入ってくる入口」で必ずこのバリデーションを通す。
こう決めておくと、 後ろ側の処理は「信頼できる配列」を前提に書けるようになり、 バグも事故もぐっと減ります。
データを信じる前に、一度疑ってみる。 その“疑い方”をコードにしたものが、配列バリデーションユーティリティです。
