Lodash _.union Behavior with Mixed Primitives

This article examines how the Lodash JavaScript library handles mixed primitive types when passed into the _.union function. It explains the internal unpacking mechanism, focusing on how Lodash flattens arguments, evaluates values against the isArrayLikeObject predicate, and filters or retains primitive types during execution.

The Internal Flattening Mechanism

Lodash defines _.union to accept multiple arrays via rest parameters, which it then processes using an internal flattening utility (baseFlatten). Specifically, _.union applies a shallow flattening step with a depth of 1 and evaluates candidates using the isArrayLikeObject validation predicate.

function union(...arrays) {
  return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
}

This predicate dictates entirely how _.union unpacks its arguments.

Direct Primitive Arguments Are Ignored

When mixed primitive values (such as numbers, strings, booleans, null, or undefined) are passed directly as arguments to _.union, they are not unpacked into the final array; they are completely discarded.

Lodash’s isArrayLikeObject helper requires a value to satisfy two conditions:

  1. It must be an object-like value (typeof value === 'object' && value !== null).
  2. It must be array-like (has a valid integer length property between 0 and Number.MAX_SAFE_INTEGER).

Because primitive values fail the isObjectLike check, they do not qualify:

// Example: Direct primitives passed as arguments
_.union([1, 2], 3, "hello", null, true);
// Output: [1, 2]

Primitives Contained Within Arrays

When mixed primitives are contained inside the array arguments passed to _.union, the unpacking behavior is different:

  1. One-Level Unpacking: The outer arrays satisfy isArrayLikeObject and are unwrapped by exactly one level.
  2. Preservation of Elements: The individual elements within those arrays—regardless of whether they are numbers, strings, booleans, objects, null, or undefined—are extracted into a single combined collection.
  3. Deduplication via SameValueZero: Lodash passes the flattened collection to baseUniq, which uses the SameValueZero comparison algorithm. This ensures that:
    • Primitives of identical type and value are deduplicated ('a' === 'a').
    • NaN values are considered equal to one another and deduplicated.
    • +0 and -0 are treated as equivalent.
// Example: Arrays containing mixed primitives
_.union([1, 'a', null, NaN], [2, 'a', undefined, NaN]);
// Output: [1, 'a', null, NaN, 2, undefined]

In summary, _.union only unpacks arguments that pass isArrayLikeObject. Direct primitive arguments are ignored, while primitives enclosed inside arrays are extracted during the single-level flatten and deduplicated using SameValueZero.