Array.prototype.flatMap()

map and flat(1) in one pass. Its quiet superpower is that returning an empty array removes the element — so it can filter and map at the same time.

Array methodES2019Live demo
Common call
items.flatMap(x => x.children)
Returns
a new array, flattened one level
Replaces
map(...).flat(), which allocates twice
Watch out
always exactly one level — there is no depth argument
array.flatMap(callback[, thisArg])
→ Array

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
factornumbermultiplier for the pair
Output
[1, 2, 3].flatMap(x => [x, x * 2])
[1, 2, 2, 4, 3, 6]

Each element becomes a two-element array, and those arrays are spliced into the result rather than nested inside it — so three inputs give six outputs. That flattening is exactly one level deep and is not configurable. Returning an empty array from the callback would contribute nothing at all, which is how flatMap doubles as a filter.

Parameters

NameTypeRequiredDescription
callbackFunctionyesCalled as callback(element, index, array). Returning an array splices its elements in; returning a non-array appends it as one element.
thisArganyno (undefined)Value of `this` inside the callback. Ignored for arrow functions.

Return value

Array — A NEW array of the callback results, flattened by exactly one level. There is no depth argument.

Common patterns

Expand each element into several
Splitting, exploding, one-to-many.
const words = lines.flatMap(l => l.split(' '));
Filter and map in one pass
An empty array drops the element.
const valid = items.flatMap(x => x.ok ? [transform(x)] : []);
Collect nested children
One level of nesting is exactly what flatMap handles.
const allChildren = nodes.flatMap(n => n.children);

Examples

1. Each becomes a pair
[1, 2].flatMap(x => [x, x * 2])
Returns
[1, 2, 2, 4]
2. Non-array appended
[1, 2].flatMap(x => x)
Returns
[1, 2]
3. Empty drops it
[1, 2, 3].flatMap(x => x > 1 ? [x] : [])
Returns
[2, 3]
4. Only one level
[1, 2].flatMap(x => [[x]])
Returns
[[1], [2]]
5. Same as map().flat()
['a b'].flatMap(s => s.split(' '))
Returns
['a', 'b']
6. Empty array
[].flatMap(x => [x])
Returns
[]

Pitfalls

1. It flattens exactly one level, always
Unlike flat there is no depth argument. A callback returning nested arrays leaves the inner ones intact, and no argument will change that — you have to chain flat afterwards.
Still nested
[1, 2].flatMap(x => [[x]])
[[1], [2]]
Chain flat
[1, 2].flatMap(x => [[x]]).flat()
[1, 2]
2. Forgetting to return an array
A non-array return is appended as a single element, so flatMap silently behaves like map. That is legal and occasionally intended, but it means a forgotten wrapper produces no error.
Behaves like map
[1, 2].flatMap(x => x * 2)
[2, 4] // no flattening happened
Return an array
[1, 2].flatMap(x => [x, x * 2])
[1, 2, 2, 4]
3. ES2019 and newer only
Missing from older runtimes and Internet Explorer. The equivalent is map followed by flat, or the older concat-spread idiom.
Missing method
items.flatMap(fn)
TypeError: items.flatMap is not a function
map then flat
items.map(fn).flat()
same result

When to use

Use it
  • One element expanding into several — splitting, exploding
  • Filtering and mapping in a single pass with [] as the drop signal
  • Collecting one level of nested children
Reach for something else
  • One value out per value in → map is clearer
  • You only need to drop elements → filter
  • Nesting deeper than one level → flat with a depth

Notes

Complexity
O(n + m) where m is the total length of the returned arrays
Return
A new array; the original is never modified
CPython impl
V8: Builtins-array-flatmap.tq
Memory
Allocates the result once, rather than the two arrays map().flat() would
Thread-safe
Single-threaded; mutating the source inside the callback is undefined behaviour for unvisited indices

FAQ

No — the depth is fixed at one and there is no argument to change it. Chain .flat() afterwards, or use map followed by flat with an explicit depth.

items.flatMap(fn).flat(Infinity)

History

ES2019
flatMap added alongside flat.