How Lodash mapKeys Transforms Object Keys

The _.mapKeys method in the Lodash JavaScript library provides an efficient way to rename or restructure the keys of an object without altering its underlying values. This article explains how _.mapKeys works under the hood, details its syntax and callback signature, and demonstrates how it maps original values to newly generated keys to produce a transformed object.

Syntax and Core Mechanics

The syntax for _.mapKeys is straightforward:

_.mapKeys(object, [iteratee=_.identity])

The method accepts two arguments:

  1. object: The source object to iterate over.
  2. iteratee: The function invoked per iteration to generate the new key.

When invoked, _.mapKeys creates a brand-new object. It iterates over the own enumerable string keyed properties of the source object and passes three arguments to the iteratee callback: (value, key, object).

The value returned by the iteratee becomes the new property name in the output object, while the original value from the source object is assigned directly to that new property.

Step-by-Step Execution

  1. Iteration: Lodash loops through each enumerable property in the target object.
  2. Key Generation: For each property, Lodash executes the iteratee function with the current property's value, key, and the entire object.
  3. Value Assignment: Whatever string (or symbol) the iteratee returns is set as the key in the newly created object. The value mapped to this key is copied directly from the original key-value pair.
  4. Immutability: The original object remains unmodified. The result is returned as a shallow copy with modified keys.

Basic Example

Consider an example where API data contains keys with unwanted prefixes or casing:

const _ = require('lodash');

const user = {
  a_name: 'Alex',
  a_role: 'Developer',
  a_id: 101
};

const sanitizedUser = _.mapKeys(user, (value, key) => {
  return key.replace('a_', '');
});

console.log(sanitizedUser);
// Output: { name: 'Alex', role: 'Developer', id: 101 }

In this scenario, _.mapKeys stripped the a_ prefix from each key, while 'Alex', 'Developer', and 101 remained tied to their respective entries.

Dynamic Key Generation Using Values

Because the iteratee receives (value, key), you can also derive keys dynamically using the values themselves:

const scores = {
  playerOne: 100,
  playerTwo: 85
};

const mappedScores = _.mapKeys(scores, (value, key) => {
  return `${key}_score_${value}`;
});

console.log(mappedScores);
// Output: { playerOne_score_100: 100, playerTwo_score_85: 85 }

Handling Key Collisions

If the iteratee returns the same key name for multiple properties, Lodash resolves the collision using standard JavaScript object behavior: subsequent assignments overwrite previous ones.

const data = {
  apple: 1,
  apricot: 2
};

const grouped = _.mapKeys(data, (value, key) => {
  return key[0]; // Returns 'a' for both
});

console.log(grouped);
// Output: { a: 2 }

Because both apple and apricot evaluate to the key 'a', the final assignment (2) overwrites the initial assignment (1). When using _.mapKeys, ensure your iteratee produces unique keys unless key deduplication is explicitly desired.