何をしたいユーティリティか:「条件抽出」
「条件抽出」は、配列の中から「ある条件に当てはまる要素だけ」を取り出す処理です。
JavaScript 標準の Array.prototype.filter を、業務で使いやすい形に“言語化”したものだと思ってください。
業務だと、例えばこういう場面で使います。
「有効なユーザーだけ」を一覧に出したい。
「ステータスが完了のものだけ」を集計したい。
「金額が 1 万円以上の明細だけ」を別の処理に回したい。
毎回 filter を直書きしても動きますが、「条件抽出ユーティリティ」としてまとめておくと、
「何を抽出しているコードなのか」が一気に読みやすくなります。
基本形:条件を関数で受け取る filterBy
「残したい条件」を関数にする
条件抽出の一番素直な形は、「残したいかどうかを判定する関数」を受け取るユーティリティです。
function filterBy(array, predicate) {
if (!Array.isArray(array)) {
return [];
}
if (typeof predicate !== "function") {
return array.slice();
}
return array.filter((item, index) => predicate(item, index));
}
JavaScriptここでの重要ポイントをかみ砕きます。
配列でなければ空配列を返す(安全側)。predicate が関数でなければ、そのままコピーして返す(何もしない)。filter の中で「残したいものだけ」を返す=predicate(...) が true のものだけ残す。
つまり、「predicate が true を返した要素だけを抽出する」ユーティリティです。
動作イメージ
例えば、「値が 0 より大きいものだけ抽出したい」場合。
const nums = [10, -5, 0, 20];
const positiveOnly = filterBy(nums, (n) => n > 0);
// [10, 20]
JavaScript「残したい条件」を n > 0 として書き、それを filterBy に渡しています。
標準の filter とやっていることは同じですが、「条件抽出」という意図が関数名に出ているのがポイントです。
よくある業務パターン別の条件抽出
ステータスで抽出する
例えば、次のような配列があるとします。
const items = [
{ id: 1, status: "active" },
{ id: 2, status: "deleted" },
{ id: 3, status: "active" },
];
JavaScript「status: "active" のものだけ抽出したい」場合。
const activeItems = filterBy(items, (item) => item.status === "active");
/*
[
{ id: 1, status: "active" },
{ id: 3, status: "active" },
]
*/
JavaScriptここでのポイントは、「残したい条件」を item.status === "active" として、
それを filterBy に渡していることです。
金額で抽出する
明細の配列から、「金額が 10,000 以上のものだけ」を抽出したいケース。
const lines = [
{ id: 1, amount: 5000 },
{ id: 2, amount: 15000 },
{ id: 3, amount: 8000 },
];
const largeLines = filterBy(lines, (line) => line.amount >= 10000);
/*
[
{ id: 2, amount: 15000 },
]
*/
JavaScript「抽出条件」が業務仕様そのものなので、
ここをユーティリティに閉じ込めておくと、後から読み返したときに意図が分かりやすいです。
条件抽出を「名前付き関数」で表現する
条件に名前を付けると一気に読みやすくなる
抽出条件が複雑になってきたら、それを名前付き関数にしておくと、コードの意図が一気に読みやすくなります。
function isActive(item) {
return item.status === "active";
}
function isLargeAmount(line) {
return line.amount >= 10000;
}
const activeItems = filterBy(items, isActive);
const largeLines = filterBy(lines, isLargeAmount);
JavaScript「この配列は“アクティブなものだけ”なんだな」「この配列は“大きな金額だけ”なんだな」と、
関数名だけで伝わります。
条件抽出は「業務ルールそのもの」なので、
ここに名前を付けておくことは、仕様書を書くのに近い意味を持ちます。
条件抽出と条件削除の関係
「残す」か「削る」かの違い
前にやった「条件削除」は、「削除したい条件」を書く関数でした。
const visibleItems = removeBy(items, (item) => item.status === "deleted");
JavaScript今回の「条件抽出」は、「残したい条件」を書く関数です。
const activeItems = filterBy(items, (item) => item.status === "active");
JavaScriptどちらも内部的には filter を使っていますが、
「頭の中で何を考えているか」が違います。
削除したい条件が仕様としてはっきりしているなら removeBy。
残したい条件で考えるほうが自然なら filterBy。
この使い分けを意識すると、コードの意図がぐっと伝わりやすくなります。
インデックスや複数条件を使った抽出
インデックスを使う
filterBy の predicate は、第 2 引数にインデックスも受け取れます。
const data = ["A", "B", "C", "D"];
const oddIndex = filterBy(data, (value, index) => index % 2 === 1);
// ["B", "D"]
JavaScript「偶数番目だけ」「奇数番目だけ」といった抽出も、同じユーティリティで書けます。
複数条件を組み合わせる
例えば、「アクティブかつ金額が 10,000 以上」のものだけ抽出したい場合。
function isActive(item) {
return item.status === "active";
}
function isLargeAmount(item) {
return item.amount >= 10000;
}
function isActiveAndLarge(item) {
return isActive(item) && isLargeAmount(item);
}
const filtered = filterBy(items, isActiveAndLarge);
JavaScript条件を小さな関数に分けて、それを組み合わせることで、
「業務ルールの組み合わせ」がコードとして見えるようになります。
条件抽出ユーティリティで意識してほしいポイント
「残したい条件」を明文化する
条件抽出は、「何を残したいか」がすべてです。
ここを関数として明文化しておくと、仕様がコードにそのまま乗ります。
isActiveisCompletedisValidAmount
こういう名前を付けておくと、「この配列は何を表しているのか」が一目で分かります。
非破壊的であること
filterBy は filter を使っているので、元の配列は変更されません。
これは意図的です。
元の配列をいじらないことで、「どこで何が抽出されたのか」が追いやすくなります。
業務コードでは、「元データはそのまま」「抽出結果を別で持つ」というスタイルのほうが、デバッグしやすく、バグも減ります。
「生の filter」と「filterBy」を使い分ける
正直、filterBy は中身としては array.filter(predicate) と同じです。
それでもユーティリティにする価値があるのは、「名前で意図を伝えられるから」です。
「ここは単に配列を絞り込んでいるだけ」なら生の filter でもいい。
「ここは業務的な“条件抽出”をしている」なら filterBy のほうが読みやすい。
このくらいの温度感で使い分けると、コードが気持ちよく整理されていきます。
手を動かして確認してみる
コンソールで、次のようなコードを実際に打ってみてください。
function filterBy(array, predicate) {
if (!Array.isArray(array)) {
return [];
}
if (typeof predicate !== "function") {
return array.slice();
}
return array.filter((item, index) => predicate(item, index));
}
const nums = [10, -5, 0, 20];
const positiveOnly = filterBy(nums, (n) => n > 0);
const items = [
{ id: 1, status: "active", amount: 5000 },
{ id: 2, status: "deleted", amount: 15000 },
{ id: 3, status: "active", amount: 20000 },
];
function isActive(item) {
return item.status === "active";
}
function isLargeAmount(item) {
return item.amount >= 10000;
}
const activeItems = filterBy(items, isActive);
const largeActiveItems = filterBy(items, (item) => isActive(item) && isLargeAmount(item));
JavaScript「どの要素が抽出されて、どの要素が落ちるか」「条件を変えると結果がどう変わるか」を、自分の目で確かめてみてください。
そのうえで、自分のプロジェクトに
export function filterBy(...) { ... }
JavaScriptを置き、「配列から“条件に合うものだけ”を取り出したくなったら、必ずこの“条件抽出ユーティリティ”を通す」と決めてみてください。
それだけで、バラバラに書かれた filter 条件が整理されて、業務ロジックの見通しがぐっと良くなります。
