flatMap とは何か
flatMap は「各要素を“変換”して、その結果を1階層だけ“平坦化(フラットに)”して新しい配列を返す」メソッドです。map と flat(1) を連続で行うのと同じ効果を、1回の処理で安全かつ読みやすく書けます。ここが重要です:flatMap は“返り値が配列のときだけ”展開します。配列以外の値はそのまま入るので、返す型を揃える設計が読みやすさの鍵です。
基本の使い方(map+flat(1) の一体化)
1階層の平坦化を伴う変換
const users = [
{ id: 1, tags: ["js", "web"] },
{ id: 2, tags: ["ai"] }
];
// map → flat(1) と同等
const allTags = users.flatMap(u => u.tags);
console.log(allTags); // ["js", "web", "ai"]
JavaScriptここが重要です:コールバックが「配列」を返すと、その中身が1階層だけ展開されます。毎回 1 階層と分かっている処理では flatMap が最短で意図が明確です。
条件によって空配列を返して“スキップ”を表現
const products = [
{ name: "A", stock: 0 },
{ name: "B", stock: 3 },
{ name: "C", stock: 2 }
];
const namesInStock = products.flatMap(p => p.stock > 0 ? [p.name] : []);
console.log(namesInStock); // ["B", "C"]
JavaScriptここが重要です:filter と map を分けず、“返す配列の中身の有無”で選別を表現できます。読みやすく 1 パスで処理できます。
map+flat の違いと使い分け
flatMap と map(…).flat() の等価性と違い
const nested = [1, [2, 3], 4];
const r1 = nested.map(x => Array.isArray(x) ? x : [x]).flat(); // [1, 2, 3, 4]
const r2 = nested.flatMap(x => Array.isArray(x) ? x : [x]); // [1, 2, 3, 4]
JavaScriptここが重要です:動作は同じですが、flatMap は“1回の走査”で済みパフォーマンスと可読性が良くなります。深さは常に 1。2階層以上の平坦化は flat(depth) を使います。
返り値が配列以外ならそのまま残る
const xs = [1, 2];
const out = xs.flatMap(x => x % 2 === 0 ? [x, x] : x);
console.log(out); // [1, 2, 2](配列は展開、非配列はそのまま)
JavaScriptここが重要です:混在させると読みにくくなるため、基本は“常に配列を返す”設計に揃えると意図が伝わります(例:あるときは [値]、無いときは [])。
空スロット(疎配列)・undefined の挙動
疎配列の“穴”は flat 同様にスキップ
const sparse = [ , [1], , [2, , 3] ]; // 空スロットを含む
const out = sparse.flatMap(x => x); // 1階層展開しつつ穴は消える
console.log(out); // [1, 2, 3]
JavaScriptここが重要です:空スロットは処理されず消えます。穴を保持したい要件では、事前に Array.from で正規化してから扱う設計にしましょう。
値としての undefined は残る
const arr = [undefined, [undefined, 1]];
console.log(arr.flatMap(x => x)); // [undefined, undefined, 1]
JavaScriptここが重要です:空スロットと undefined を混同しないこと。欠損をゼロ埋めしたいなら null 合体演算子(??)で明示的に埋めます。
実務での定番レシピ
ネスト配列の一括抽出(中身だけ欲しい)
const groups = [
{ name: "A", items: [1, 2] },
{ name: "B", items: [3] }
];
// items を集めて1本の配列へ
const allItems = groups.flatMap(g => g.items); // [1, 2, 3]
JavaScript部分的な展開+変換(タグを“表示ラベル”へ)
const users = [
{ name: "Alice", tags: ["js", "web"] },
{ name: "Bob", tags: ["ai"] }
];
const labels = users.flatMap(u => u.tags.map(t => `${u.name}:${t}`));
// ["Alice:js","Alice:web","Bob:ai"]
JavaScriptここが重要です:返す配列の中でさらに map して、展開と変換を一度に記述できます。
条件抽出を 1 パスで(filter+map を合成)
const products = [
{ name: "A", stock: 0, price: 100 },
{ name: "B", stock: 5, price: 200 },
{ name: "C", stock: 3, price: 150 }
];
const labels = products.flatMap(p => p.stock > 0 ? [`${p.name} (${p.price})`] : []);
// ["B (200)","C (150)"]
JavaScriptここが重要です:“あるなら1件の配列、無ければ空配列”という定型で、絞り込みと変換を同時に書けます。
Object.values と組み合わせて辞書の値を統合
const catalog = {
fruits: ["apple","banana"],
vegs: ["carrot"]
};
const all = Object.values(catalog).flatMap(xs => xs); // ["apple","banana","carrot"]
JavaScriptパフォーマンスと設計の指針
1階層が確定なら flatMap が最短で効率的
map→flat(1) と比べて、flatMap は1パスで意図が明確。読み手に「返り値は配列で、1階層だけ展開する」と伝えられます。
深い階層は flat(depth) か専用ロジックへ
2階層以上の平坦化は flat(depth) を使うか、要件が複雑なら再帰・スタックで明示的に処理します。flatMap はあくまで“1階層”に特化した道具です。
返り値の型を揃える(常に配列を返す)
返り値が配列と非配列の混在は、意図を読みづらくします。原則「返り値は配列。不要なら空配列」を徹底すると、後続処理が安定します。
よくある落とし穴と回避策
コールバックで非配列を返してしまう
非配列は展開されずそのまま入ります。常に配列を返す設計(例:条件 ? [値] : [])にすると誤動作を防げます。
2階層以上を展開したいのに flatMap を使う
flatMap は 1 階層のみ。多段なら map(...).flat(2) または flat(2) に切り替えます。
疎配列の穴が消えて困る
空スロットはスキップされます。穴を扱いたいなら正規化してから flatMap、または Array.from で埋めてから処理します。
複雑すぎるロジックを flatMap に詰め込みすぎる
分岐・重い処理・多段変換を詰め込むと可読性が落ちます。必要に応じてステップを分ける(前処理→flatMap→後処理)方が保守しやすいです。
まとめ
flatMap は「各要素を変換し、その結果を1階層だけ平坦化して“新しい配列”を返す」非破壊メソッドです。map+flat(1) を1回で表現でき、“配列を返す”という意図が明確。疎配列の穴はスキップされ、undefined は残るため、欠損の扱いは設計で意識する。返り値は配列に統一し、2階層以上は flat(depth) へ。この指針を押さえれば、初心者でも“絞り込み+変換+統合”を短く正確に書けます。
