How Lodash _.transform Infers Accumulator Type
The Lodash _.transform method provides an ergonomic
alternative to _.reduce, allowing developers to iterate
over collections and mutate an accumulator directly without explicitly
returning it in each cycle. When the accumulator argument is omitted,
Lodash automatically determines its initial type by inspecting the
constructor, prototype, and underlying data structure of the source
collection, defaulting to a new instance that mirrors the original
target.
The Accumulator Resolution Strategy
When you invoke _.transform(collection, iteratee)
without passing a third argument, Lodash determines the initial
accumulator using the following resolution hierarchy:
1. Arrays and Array-Like Structures
If the input collection is an Array, Lodash creates a new instance
using the source array's constructor
(new object.constructor or a fresh []). For
other array-like structures, such as typed arrays or Buffers, Lodash
defaults to an empty standard array ([]) to avoid
unintended memory or buffer-size constraints during mutation.
const sourceArray = [1, 2, 3];
const result = _.transform(sourceArray, (acc, val) => {
acc.push(val * 2);
});
console.log(Array.isArray(result)); // true
console.log(result); // [2, 4, 6]2. Objects and Custom Prototypes
If the collection is an object, Lodash attempts to preserve its
prototype chain. Rather than simply instantiating a plain
{} literal:
- If the object has a valid constructor function, Lodash creates a new
object that shares the prototype of the original using
Object.create(Object.getPrototypeOf(object)). - If prototype resolution fails or the object does not have a standard
constructor, it falls back to a plain object literal
(
{}).
This prototype inheritance ensures that custom class instances
transformed via _.transform retain their inherited methods
on the resulting accumulator:
class BaseConfig {
isValid() {
return true;
}
}
const configInstance = Object.assign(new BaseConfig(), { a: 1, b: 2 });
const transformed = _.transform(configInstance, (acc, val, key) => {
acc[key] = val * 10;
});
console.log(transformed instanceof BaseConfig); // true
console.log(transformed.isValid()); // true3. Primitives and Fallbacks
If the target passed to _.transform is neither an
array-like entity nor a standard object (such as null,
undefined, or primitive values), Lodash initializes the
accumulator as a fresh, empty object ({}).
Why the Default Inference Matters
By automatically checking constructor properties and the prototype
chain, _.transform eliminates boilerplate code. Developers
do not need to manually pass [] when transforming arrays or
worry about losing prototype methods when working with instances of
custom classes. If a transformation requires a distinct target type—such
as converting an object's key-value pairs into an array—an explicit
accumulator must still be provided as the third parameter.