Array.prototype.flatMap()
Maps each element to zero or more values and flattens the results one level into a new array.
flatMap(callbackFn)
flatMap(callbackFn, thisArg)- Added in JavaScript ECMAScript 2019
Parameters
| Parameter | Type | Description |
|---|---|---|
$callbackFn | (element: any, index: number, array: Array) => any | Runs for each element. Return an array of values to splice into the result, or a single non-array value to append as-is. |
$thisArgoptional | any= undefined | Value used as this inside callbackFn. Ignored for arrow functions. |
Return value
ArrayA new array with each element being the result of the callback function, flattened by a depth of 1.
Errors
Throws a TypeError if callbackFn is not callable, or if the method is called on null or undefined.
flatMap() is map() followed by flat(1), done in a single pass without building the intermediate array. Its real value is that the callback is not limited to returning exactly one value per element: return an array of two to expand, and return an empty array to drop the element entirely.
When to reach for it
Reach for it when the shape of the output does not match the shape of the input — splitting text into words, expanding an order into its line items, or doing a filter and a map together in one traversal. The filter-and-map pattern is the most useful one:
list.flatMap((x) => (keep(x) ? [transform(x)] : []))What trips people up
- The flattening depth is fixed at 1. If your callback returns nested arrays, the outer level is removed and the inner one survives — chain
.flat()or return flatter values. - Empty slots in a sparse source array are skipped, and empty slots inside returned arrays are dropped.
- The visited range is fixed before the first call, so elements appended by the callback are never visited.
Like map(), it always allocates a new array; if you only need a side effect, use for...of instead.
Example
When to use it
- Split a list of sentences into a single flat array of words.
- Filter and transform in one pass by returning [] for items you want to drop.
- Expand each order in a list into its individual line items.
- Emit two derived records per input row without a second flatten step.
Frequently asked questions
What is the difference between map() and flatMap()?
flatMap() flattens the callback's results one level, so a callback returning an array contributes several elements instead of one nested array. map() always produces exactly one output element per input element.
How do I filter and map at the same time in JavaScript?
Use flatMap() and return [value] to keep an element or [] to drop it. This does one traversal instead of the two that filter().map() needs, and it lets you compute the transformed value only for the items you keep.
Can flatMap() flatten more than one level?
No, the flattening depth is fixed at 1 and there is no depth parameter. Chain .flat(Infinity) after it, or return already-flat arrays from the callback.
More examples
Expanding records into rows
Each order contributes as many rows as it has items. Order B contributes none because its inner map produced an empty array, so the result has 3 rows from 3 orders.
const orders = [
{ id: "A", items: ["pen", "pad"] },
{ id: "B", items: [] },
{ id: "C", items: ["ink"] },
];
const rows = orders.flatMap((o) => o.items.map((item) => `${o.id}:${item}`));
console.log(rows);
console.log(rows.length);Only one level is flattened
The second call returns arrays of arrays; flatMap removes only the outer wrapper, leaving [[2], [4]]. An extra .flat() is needed to reach [2, 4].
console.log([1, 2].flatMap((n) => [n * 2]));
console.log([1, 2].flatMap((n) => [[n * 2]]));
// Chain flat() if the callback nests deeper
console.log([1, 2].flatMap((n) => [[n * 2]]).flat());Callback arguments and thisArg
The callback receives element, index and the source array. Passing thisArg binds this inside a normal function expression; it has no effect on arrow functions.
const labels = ["a", "b"];
console.log(labels.flatMap((el, i, arr) => [`${i}/${arr.length}:${el}`]));
const tagger = { tag: "x" };
console.log(
labels.flatMap(function (el) {
return [this.tag + el];
}, tagger),
);
Discussion