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:
- 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. - Shared References: Returning a pre-defined symbol reference ensures all matching values group under that specific identifier.
- 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:
- Direct Access: Properties can be accessed using
bracket notation if the symbol reference is available:
grouped[symAdmin]. - Standard Iteration: Functions such as
Object.keys(),Object.values(),Object.entries(), and standardfor...inloops ignore symbol keys. Lodash’s own_.keys()also skips symbol properties. - Symbol Retrieval: To inspect or iterate over
symbol-based groups, use
Object.getOwnPropertySymbols(grouped)to retrieve an array of symbols, orReflect.ownKeys(grouped)to retrieve both string and symbol keys.
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.