Lodash sortedIndexBy with Mixed Data Types

Lodash's _.sortedIndexBy method determines the lowest index at which a value should be inserted into a sorted array to maintain its sort order, utilizing an iteratee (transformer) function to compute the comparison criteria. When applied to collections containing mixed data types, the transformer is called uniformly on both the array elements and the search value, but the ultimate insertion index depends on whether the transformer normalizes these mixed types or leaves them to JavaScript's standard type coercion rules during binary search comparisons.

How the Transformer Function Executes

The syntax for the method is _.sortedIndexBy(array, value, [iteratee=_.identity]). Internally, Lodash implements a binary search algorithm (baseSortedIndexBy) that executes the iteratee function in two contexts:

  1. On the Target Value: The iteratee evaluates the target value once to obtain a derived comparison value.
  2. On Array Elements: As the binary search bisects the array, the iteratee is applied on-demand to the element at the midpoint (array[mid]).

The transformer does not inspect or validate the type of data it receives unless explicitly coded to do so. It simply maps each raw element into a transformed output value.

// Example transformer extracting a property
const array = [{ val: 10 }, { val: '20' }, { val: 30 }];
const index = _.sortedIndexBy(array, { val: 15 }, (o) => o.val);

Binary Comparison of Mixed Types

Once the transformer returns values for both the target and the array midpoint, Lodash compares them using standard relational comparison operators (<). When mixed data types exist, two distinct scenarios occur depending on the iteratee's implementation:

1. Unnormalized Transformers (Coercion Risks)

If the transformer simply passes through properties without normalizing their types (such as numbers and numeric strings), JavaScript's Abstract Relational Comparison algorithm dictates the outcome:

Because binary search relies strictly on the mathematical assumption of transitivity (\(A < B\) and \(B < C\) implies \(A < C\)), mixed types that do not evaluate predictably break the search logic.

2. Normalizing Transformers (Predictable Ordering)

To reliably use _.sortedIndexBy with mixed data types, the transformer function itself should homogenize the types prior to the comparison step.

const mixedArray = ['2', 5, '10', 25];

// The transformer converts all elements to numbers before comparison
const insertIndex = _.sortedIndexBy(mixedArray, '15', (item) => Number(item));
// Returns 3

By enforcing a single primitive type (such as explicitly casting via Number(), String(), or generating a custom sort weight), the transformer prevents implicit type coercion, ensuring the binary search behaves deterministically across heterogeneous collections.