How Lodash groupBy Handles Symbol Keys

This article provides a technical overview of how the Lodash _.groupBy function handles JavaScript Symbol primitives returned by an iteratee. It covers internal property assignment, the distinction between unique and global symbols, key visibility during object traversal, and serialization constraints.

Direct Property Assignment Without Coercion

Modern Lodash (v4+) handles Symbol return values natively. Internally, _.groupBy uses an aggregator function that evaluates the iteratee for each collection item and assigns values using standard property accessor syntax (accumulator[key]).

Because ECMAScript 2015 (ES6) allows both strings and symbols as valid object property keys, Lodash assigns the grouped array directly to the symbol property without performing string coercion (such as key + '' or String(key)). This implementation prevents the TypeError: Cannot convert a Symbol value to a string exception that typically occurs when symbols are implicitly converted into strings.

const _ = require('lodash');

const symAdmin = Symbol('admin');
const symUser = Symbol('user');

const accounts = [
  { id: 1, role: symAdmin },
  { id: 2, role: symUser },
  { id: 3, role: symAdmin }
];

const grouped = _.groupBy(accounts, account => account.role);

// grouped contains:
// { [Symbol(admin)]: [{ id: 1, ... }, { id: 3, ... }], [Symbol(user)]: [{ id: 2, ... }] }

Symbol Identity and Grouping Behavior

Grouping relies strictly on ECMAScript equality for object property access:

  1. Unique Symbols: If the iteratee calls Symbol('name') inline rather than returning an existing reference, each returned symbol is unique. Consequently, every item is assigned to a separate property key, preventing items from grouping together.
  2. Shared References: Returning a pre-defined symbol reference ensures all matching values group under that specific identifier.
  3. Global Symbol Registry: If the iteratee uses Symbol.for('key'), values group under the shared registry symbol corresponding to that key string.

Inspecting and Accessing Symbol-Keyed Groups

Objects with symbol keys behave differently from standard string-keyed objects during inspection and iteration:

const symbols = Object.getOwnPropertySymbols(grouped);
symbols.forEach(sym => {
  console.log(sym, grouped[sym]);
});

JSON Serialization Limitations

Standard JSON serialization does not support symbols. If a _.groupBy result containing only symbol keys is passed to JSON.stringify(), the output will be an empty object ({}). If the data must be serialized for APIs or storage, symbol keys must be converted to strings (e.g., using sym.description or sym.toString()) before or during serialization.