oxc-project/oxc · warning · OxcDiagnostic
Avoid using a negative index with `Array#with()`.
Error message
Avoid using a negative index with `Array#with()`.
What it means
Diagnostic from the oxlint rule `unicorn/no-confusing-array-with` (negative-index arm, category: suspicious). `Array.prototype.with(index, value)` interprets a negative index as an offset from the end of the array — unlike `slice()`/`splice()` intuition — so `array.with(-1, v)` replaces the last element. Because that surprises most readers, the rule flags statically negative indexes and asks for a non-negative position instead.
Source
Thrown at crates/oxc_linter/src/rules/unicorn/no_confusing_array_with.rs:14
use oxc_ast::{
AstKind,
ast::{Expression, UnaryOperator},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{
AstNode, ast_util::is_method_call, context::LintContext, rule::Rule, utils::is_same_expression,
};
fn negative_index_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Avoid using a negative index with `Array#with()`.")
.with_note("`Array#with()` interprets a negative index as an offset from the end.")
.with_help("Use a non-negative index to make the intended position explicit.")
.with_label(span)
}
fn length_index_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Avoid using `.length` as the index in `Array#with()`.")
.with_note("An array's `.length` is one past its last valid index.")
.with_help("Use `.length - 1` to replace the last element.")
.with_label(span)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ConfusingWithIndex {
Negative,
Length,
}
View on GitHub (pinned to e1e7af627c)
Solutions
- Rewrite with an explicit non-negative index: `array.with(array.length - 1, value)` targets the last element
- Store the position in a variable (`const last = items.length - 1;`) when the same offset is reused
- If the end-relative offset is intentional and agreed, suppress once with `// oxlint-disable-next-line unicorn/no-confusing-array-with`
Example fix
// before const updated = items.with(-1, 'last'); // after const updated = items.with(items.length - 1, 'last');
Defensive patterns
Strategy: validation
Validate before calling
// explicit, lint-clean helper for end-relative replacement
function withFromEnd(arr, offsetFromEnd, value) {
const index = arr.length - 1 - offsetFromEnd;
if (index < 0) throw new RangeError('offset past start');
return arr.with(index, value);
} Prevention
- Prefer non-negative indexes in `.with()`; reserve negative indexes for `.at()`
- Unit-test boundary positions (0, length-1, length) whenever `.with()` is introduced
- Enable unicorn/no-confusing-array-with in CI rather than relying on review
When it happens
Trigger: Any `x.with(idx, ...)` call whose first argument statically evaluates to a negative number: `array.with(-1, value)`, `array.with(-2, value)`, `array.with(-1.5, value)`, `array.with(-(-(-1)))`. Dynamic indexes (`array.with(i)`), `-0`, `+1`, and `-1e400` (not finite-negative by truncation rules) pass.
Common situations: Porting `.at(-1)` or negative-splice idioms to the newer ES2023 `.with()`; adopting change-by-copy methods in codebases that had polyfills with different semantics; code review disputes about negative indexes.
Related errors
- Avoid using `.length` as the index in `Array#with()`.
- Avoid calls to the `Array` constructor
- Unexpected comma in middle of array
- {} unexpected commas in middle of array
- Use Array destructuring.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/2bd334d39103d8a4.
Report an issue: GitHub.