何をしたいユーティリティか:「条件変換」
「条件変換」は、配列の中の「条件に合う要素だけ」を変換し、それ以外はそのまま残す処理です。
英語で言うと mapIf、mapWhen、conditionalMap みたいなイメージです。
業務だと、例えばこういう場面で使います。
特定ステータスのレコードだけフラグを書き換えたい。
金額がマイナスの明細だけを 0 に補正したい。
特定ユーザーだけ表示名を変えたいが、他はそのままにしたい。
普通の map は「全部の要素を変換する」前提ですが、
条件変換は「一部だけ変換して、残りはそのまま」というところがポイントです。
基本形:条件と変換関数を受け取る mapIf
まずは「条件に合うときだけ変換する」関数
一番素直な形は、「変換するかどうかを決める条件」と「実際の変換処理」を分けて受け取るユーティリティです。
function mapIf(array, predicate, mapper) {
if (!Array.isArray(array)) {
return [];
}
if (typeof predicate !== "function" || typeof mapper !== "function") {
return array.slice();
}
return array.map((item, index) => {
if (predicate(item, index)) {
return mapper(item, index);
}
return item;
});
}
JavaScriptここでの重要ポイントをかみ砕きます。
配列でなければ空配列を返す(安全側)。predicate(条件)か mapper(変換)が関数でなければ、そのままコピーして返す。map の中で「条件に合うときだけ mapper を適用し、合わないときは元の要素をそのまま返す」。
つまり、「条件に合う要素だけ変換し、それ以外はそのまま」という動きになります。
動作イメージ
例えば、「0 未満の数値だけ 0 に補正したい」場合。
const nums = [10, -5, 0, 20, -3];
const normalized = mapIf(
nums,
(n) => n < 0, // 条件:負の数
(n) => 0 // 変換:0 にする
);
// [10, 0, 0, 20, 0]
JavaScriptmap だけで書こうとすると「負のときは 0、それ以外は n」という if を毎回書くことになりますが、mapIf にすると「条件」と「変換」がきれいに分かれます。
よくある業務パターンでの条件変換
ステータスに応じてフラグを変換する
例えば、次のような配列があるとします。
const items = [
{ id: 1, status: "active", archived: false },
{ id: 2, status: "deleted", archived: false },
{ id: 3, status: "active", archived: false },
];
JavaScript「status: "deleted" のものだけ archived: true にしたい」場合。
const updated = mapIf(
items,
(item) => item.status === "deleted",
(item) => ({ ...item, archived: true })
);
/*
[
{ id: 1, status: "active", archived: false },
{ id: 2, status: "deleted", archived: true },
{ id: 3, status: "active", archived: false },
]
*/
JavaScriptここでのポイントは、「削除済みだけ変換」「他はそのまま」という意図が、predicate と mapper にきれいに分かれていることです。
特定ユーザーだけ表示名を変える
const users = [
{ id: 1, name: "Taro" },
{ id: 2, name: "Hanako" },
{ id: 3, name: "Admin" },
];
const masked = mapIf(
users,
(u) => u.name === "Admin",
(u) => ({ ...u, name: "[管理者]" })
);
/*
[
{ id: 1, name: "Taro" },
{ id: 2, name: "Hanako" },
{ id: 3, name: "[管理者]" },
]
*/
JavaScript「Admin だけ表示名を変える」という要件を、
条件と変換に分けて素直に書けます。
条件と変換を「名前付き関数」にすると一気に読みやすくなる
条件に名前を付ける
条件が業務ルールそのものなので、名前付き関数にしておくと意図が伝わりやすくなります。
function isDeleted(item) {
return item.status === "deleted";
}
function isNegative(n) {
return n < 0;
}
JavaScript変換にも名前を付ける
変換も同じく、「何をしたいか」を名前にします。
function archive(item) {
return { ...item, archived: true };
}
function toZero() {
return 0;
}
JavaScript組み合わせて使う
const archivedItems = mapIf(items, isDeleted, archive);
const normalizedNums = mapIf(nums, isNegative, toZero);
JavaScriptこれだけで、「削除済みをアーカイブする」「負の数を 0 にする」という意図が、
コードを読んだ瞬間に伝わります。
条件変換と普通の map の違いを整理する
普通の map
map は「全部の要素を変換する」前提です。
const doubled = nums.map((n) => n * 2);
JavaScript全要素に対して同じ変換をかけるときは、これで十分です。
条件変換(mapIf)
mapIf は、「条件に合う要素だけ変換し、それ以外はそのまま」です。
const normalized = mapIf(nums, (n) => n < 0, () => 0);
JavaScript「一部だけ変えたい」「他は触りたくない」というときに、map で if を書くより、mapIf のほうが意図がはっきりします。
インデックスや複数条件を使った条件変換
インデックスを使う
predicate と mapper は、第 2 引数にインデックスも受け取れます。
const data = ["A", "B", "C", "D"];
const withStarOnOdd = mapIf(
data,
(value, index) => index % 2 === 1,
(value) => value + "*"
);
// ["A", "B*", "C", "D*"]
JavaScript「奇数番目だけマークを付ける」といった変換も、同じユーティリティで書けます。
複数条件を組み合わせる
例えば、「アクティブかつ金額が 10,000 以上のものだけ、ラベルを付けたい」場合。
function isActive(item) {
return item.status === "active";
}
function isLargeAmount(item) {
return item.amount >= 10000;
}
function markAsImportant(item) {
return { ...item, important: true };
}
const marked = mapIf(
items,
(item) => isActive(item) && isLargeAmount(item),
markAsImportant
);
JavaScript条件を小さな関数に分けて、それを組み合わせることで、
「どんな条件のときにどう変換しているか」が、仕様レベルで見えるようになります。
条件変換ユーティリティで意識してほしいポイント
「変えるもの」と「変えないもの」をはっきり分ける
条件変換の本質は、「変えるもの」と「変えないもの」を明確に分けることです。
条件に合うものだけ mapper を適用し、
条件に合わないものはそのまま返す。
このパターンをユーティリティにしておくと、
「一部だけ変えたい」という処理がすべて同じ形で書けるようになります。
非破壊的にする(新しい配列を返す)
mapIf は map を使っているので、元の配列は変更されません。
これは意図的です。
元の配列をいじらないことで、「どこで何が変換されたのか」が追いやすくなります。
業務コードでは、「元データはそのまま」「変換結果を別で持つ」というスタイルのほうが、デバッグしやすく、バグも減ります。
条件・変換を小さく分けて再利用する
条件(predicate)と変換(mapper)を小さな関数に分けておくと、
別の場所でも同じルールを再利用できます。
isActiveisDeletedisNegative
archivetoZeromarkAsImportant
こういう小さな部品を増やしていくと、
「業務ルールのライブラリ」を自分で持っているような感覚になってきます。
手を動かして感覚をつかむ
コンソールで、次のようなコードを実際に打ってみてください。
function mapIf(array, predicate, mapper) {
if (!Array.isArray(array)) {
return [];
}
if (typeof predicate !== "function" || typeof mapper !== "function") {
return array.slice();
}
return array.map((item, index) =>
predicate(item, index) ? mapper(item, index) : item
);
}
const nums = [10, -5, 0, 20, -3];
const normalized = mapIf(nums, (n) => n < 0, () => 0);
const items = [
{ id: 1, status: "active", amount: 5000 },
{ id: 2, status: "deleted", amount: 15000 },
{ id: 3, status: "active", amount: 20000 },
];
function isDeleted(item) {
return item.status === "deleted";
}
function archive(item) {
return { ...item, archived: true };
}
const archivedItems = mapIf(items, isDeleted, archive);
JavaScript「どの要素が変換されて、どの要素がそのままか」「条件や変換を変えると結果がどう変わるか」を、自分の目で確かめてみてください。
そのうえで、自分のプロジェクトに
export function mapIf(...) { ... }
JavaScriptを置き、「配列の一部だけを条件付きで変換したくなったら、必ずこの“条件変換ユーティリティ”を通す」と決めてみてください。
それだけで、「map の中に if がべったり書かれたコード」から、一段整理された設計に進めます。
