The Array.prototype.flatMap() method is a powerful combination of two other array methods: map() followed by flat() with a depth of 1. It allows you to iterate through an array, transform each element into a new value (which can be an array of values), and then flatten the resulting nested structure into a single-level array.
This method is significantly more efficient than calling map().flat() separately because it performs both operations in a single pass through the data, saving memory and processing time.
1. Syntax and the Callback Function
The method takes a callback function that defines how each element should be transformed.
const newArray = array.flatMap((currentValue, index, array) => {
// return element(s) for the new array
}, thisArg);
- Callback: Executed for every element, returning either a single value, an array of values, or an empty array.
- Depth Limitation: Unlike the .flat() method, which allows you to specify a depth (e.g., flat(Infinity)), flatMap() only flattens to a depth of 1.
Simple Example:
Imagine you have an array of numbers and you want to create a new array where each number is followed by its square.
const nums = [1, 2, 3];
const result = nums.flatMap(n => [n, n * n]);
console.log(result); // [1, 1, 2, 4, 3, 9]
// Equivalent to:
// nums.map(n => [n, n * n]).flat(1)
2. The Power of “One-to-Many” Mapping
While a standard .map() always results in an array of the same length as the original, flatMap() allows an input element to produce multiple output elements.
const sentences = ["Hello world", "The DOM is cool"];
// goal: Get a list of all words
const words = sentences.flatMap(s => s.split(" "));
console.log(words);
// ["Hello", "world", "The", "DOM", "is", "cool"]
If we used .map() in the example above, we would have ended up with a nested array: [["Hello", "world"], ["The", "DOM", "is", "cool"]]. flatMap() automatically unwraps that first level of nesting for us.
3. The “Filter-Map” Pattern
One of the most useful tricks with flatMap() is its ability to add or remove elements from the resulting array during the mapping process. By returning an empty array [] for an element, you effectively “filter” it out.
const words = ["apple", "", "banana", " ", "cherry"];
const cleanWords = words.flatMap(word => {
return word.trim() === "" ? [] : [word.toUpperCase()];
});
console.log(cleanWords); // ["APPLE", "BANANA", "CHERRY"]
[Image comparing JavaScript map-then-filter vs flatMap for data cleaning]
4. Technical Constraints: Depth Matters
It is vital to remember that flatMap() is strictly a shallow flatten. If your mapping function returns an array that contains another nested array, only the first level will be dissolved.
const numbers = [1, 2, 3];
const deep = numbers.flatMap(n => [[n * 10]]);
console.log(deep); // [[10], [20], [30]]
// Only the outer array returned by the callback was flattened.
If you require deeper flattening, you must use .map() followed by .flat(depth).
5. Real-World Use Case: Expanding Data Structures
Imagine you have a list of products, and each product has an array of “alternative sizes.” You want a single flat list of every possible product/size combination available in your inventory.
const inventory = [
{ name: "T-Shirt", sizes: ["S", "M", "L"] },
{ name: "Hat", sizes: ["One Size"] }
];
const allSKUs = inventory.flatMap(item =>
item.sizes.map(size => `${item.name} - ${size}`)
);
console.log(allSKUs);
// ["T-Shirt - S", "T-Shirt - M", "T-Shirt - L", "Hat - One Size"]
In this scenario, flatMap() acts as an orchestrator that “explodes” the data into its constituent parts while keeping the resulting structure flat and ready for display in a UI component.
