Array.map and Immutability
Why This Is Asked
This is a fundamental question to check if a developer understands the difference between mutating and non-mutating array methods. It is especially important in frameworks like React where immutability is required for efficient change detection.
Key Concepts
Array.prototype.map()creates a new array with the results of calling a provided function on every element.- It does not mutate the original array.
- The new array has the same length as the original array.
- If the elements are objects, the new array will contain references to the same objects (shallow copy) unless you explicitly clone them in the callback.
Answers by Technology
+ Add VariantExpected Answer
Yes, Array.map() always creates a new array.
It iterates over the original array and executes a callback function for each element. The return value of that callback is placed into the same index of a new array, which is then returned after the iteration is complete. The original array remains unchanged.
Why It Matters
In modern JavaScript development (especially with React, Redux, or Vue), immutability is a core principle. You should not modify existing state; instead, you create new versions of it. map() is the standard tool for transforming data without side effects. If you don’t need the returned array, you should probably use forEach() instead.
Example Code
Basic Usage
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
console.log(numbers); // [1, 2, 3] (Original unchanged)
console.log(doubled); // [2, 4, 6] (New array)
Shallow Copy Warning
If the array contains objects, map() creates a new array, but the elements in that new array still point to the same objects in memory.
const users = [{ name: 'Alice' }, { name: 'Bob' }];
const newUsers = users.map(u => u);
newUsers[0].name = 'Charlie';
console.log(users[0].name); // 'Charlie' (Mutation!)
Common Mistakes
- Not returning a value from the callback: If you forget the
returnstatement (or don’t use an implicit return), the new array will be full ofundefined. - Using
mapwhenforEachis appropriate: If you aren’t using the returned array and are just performing side effects (like logging),forEachis more semantically correct and slightly more performant. - Mutating elements inside
map: Developers sometimes modify the elements of the original array inside themapcallback. This defeats the purpose of using a non-mutating method.
Follow-up Questions
- What is the difference between
map()andforEach()? (Answer:mapreturns a new array,forEachreturnsundefined). - Does
filter()also create a new array? (Answer: Yes, it returns a new array containing only elements that pass the predicate). - How would you create a deep copy of an array of objects using
map()? (Answer: By returning a clone of each object, e.g.,arr.map(obj => ({ ...obj }))).
References
Expected Answer
Yes, Array.map() creates a new array. In TypeScript, map is a generic method that allows for type-safe transformations.
The signature looks roughly like this:
map<U>(callbackfn: (value: T, index: number, array: T[]) => U): U[]
This means that if you have an array of type T[], and your callback returns a value of type U, map will return a new array of type U[].
Why It Matters
TypeScript’s type inference makes map extremely powerful for data transformation. It ensures that the resulting array’s type is correctly tracked through your application, preventing “property undefined” errors that often occur when manually iterating and pushing to a new array.
Example Code
Type Transformation
interface User {
id: number;
name: string;
}
const users: User[] = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
// Automatically inferred as string[]
const names = users.map(user => user.name);
Readonly Arrays
If you are using ReadonlyArray<T>, map is one of the few methods available because it does not mutate the original.
const nums: readonly number[] = [1, 2, 3];
// nums.push(4); // Error: Property 'push' does not exist
const doubled = nums.map(n => n * 2); // OK: returns a new array
Common Mistakes
- Incorrect Type Casting: Sometimes developers try to cast the result of
mapinstead of letting TypeScript infer it, which can hide bugs if the callback logic changes. - Handling Optional Properties: When mapping objects with optional properties, ensure your callback handles
undefinedvalues correctly to maintain type safety in the resulting array.
Follow-up Questions
- How does TypeScript handle the type of the new array? (Answer: It uses generics. The type of the output array is determined by the return type of the callback function).
- Can
mapchange the type of the elements? (Answer: Yes, this is one of its primary uses—for example, mapping a list of domain objects to a list of UI ViewModels).