How Lodash _.slice Handles String Parameters
This article explains how the Lodash _.slice method
processes start and end parameters when they
are intentionally passed as string values. Unlike JavaScript's native
Array.prototype.slice, which automatically converts string
parameters into numbers, Lodash relies on strict type checks that alter
how string inputs are resolved, often leading to unexpected results such
as returning empty arrays.
Strict Type Checking in Lodash
Lodash implements _.slice as an optimized alternative to
the native Array.prototype.slice. Rather than performing
standard JavaScript type coercion (such as
ToIntegerOrInfinity), Lodash inspects parameter types
directly using the typeof operator.
The internal logic determines positional offsets by verifying whether arguments are strictly numbers:
- If
typeof start === 'number', it handles negative offsets and index boundaries normally. Iftypeof startis anything else (including a string), Lodash defaultsstartto0. - If
typeof end === 'number', it resolves negative offsets and applies bounds. Iftypeof endis not a number, it defaultsendto0under most conditions.
How String Values for
start Behave
When you pass a string as the start parameter (e.g.,
_.slice(array, '2')), the type check
typeof start === 'number' evaluates to
false.
Because Lodash does not convert string numbers into numerical primitives:
startis reset to0.- Slicing begins at index
0, ignoring the intended string value.
const items = ['a', 'b', 'c', 'd'];
// Passing a string start:
_.slice(items, '2');
// Returns: ['a', 'b', 'c', 'd'] (start falls back to 0)How String Values for
end Behave
The behavior for a string end argument depends on how
JavaScript evaluates relational comparisons before the type check
occurs.
Internally, Lodash first checks:
end = end > length ? length : end;When
endis less than or equal tolength: Evaluating'2' > 4uses standard relational coercion, resulting infalse. Lodash retainsend = '2'. It then runsif (typeof end === 'number'). Because'2'is a string, this condition fails, triggering the fallback:end = 0. Sincestartandendboth resolve to0,_.sliceproduces an empty array ([]).When
endis greater thanlength: Evaluating'5' > 4coerces'5'to a number and returnstrue. Lodash reassignsend = length. Becauselengthis an integer primitive,typeof end === 'number'now evaluates totrue, andendremains bounded to the array's full length.
const items = ['a', 'b', 'c', 'd'];
// String end <= length:
_.slice(items, 0, '2');
// Returns: [] (end falls back to 0)
// String end > length:
_.slice(items, 0, '10');
// Returns: ['a', 'b', 'c', 'd'] (end is replaced by array length: 4)Difference from
Native Array.prototype.slice
JavaScript's native Array.prototype.slice coerces
arguments to integers using standard ECMAScript conversions:
const items = ['a', 'b', 'c', 'd'];
// Native slice coerces strings to numbers:
items.slice('1', '3');
// Returns: ['b', 'c']
// Lodash _.slice does not coerce strings:
_.slice(items, '1', '3');
// Returns: [] (start becomes 0, end becomes 0)Handling String Inputs Properly
To avoid unexpected empty arrays or incorrect slices when dealing
with string values (such as URL parameters or form inputs), explicitly
convert the arguments to numbers before calling
_.slice:
const start = Number('1');
const end = Number('3');
_.slice(items, start, end);
// Returns: ['b', 'c']