oxc-project/oxc · error · OxcDiagnostic

Avoid using `.length` as the index in `Array#with()`.

Error message

Avoid using `.length` as the index in `Array#with()`.

What it means

Diagnostic from the oxlint rule `unicorn/no-confusing-array-with` (length-index arm, category: suspicious). Valid `.with()` indexes are `0..length-1`; `.with()` replaces an element and cannot append, so passing `arr.length` (one past the last valid index) always throws a RangeError at runtime. The rule catches this statically whenever the index is a `.length` member access on an expression provably identical to the call receiver, converting a guaranteed crash into a lint-time error.

Source

Thrown at crates/oxc_linter/src/rules/unicorn/no_confusing_array_with.rs:21

    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,
}

#[derive(Debug, Default, Clone)]
pub struct NoConfusingArrayWith;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallows confusing uses of [`Array#with()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/with).

View on GitHub (pinned to e1e7af627c)

Solutions

  1. To append immutably, use spread: `const next = [...items, item]`
  2. To replace the last element, use `items.with(items.length - 1, item)`
  3. If the index is computed at runtime, validate it first: `if (!Number.isInteger(i) || i < 0 || i >= arr.length) throw new RangeError(...)`

Example fix

// before (always throws RangeError)
const next = items.with(items.length, 'new');

// after
const next = [...items, 'new'];
Defensive patterns

Strategy: validation

Validate before calling

function safeWith(arr, index, value) {
  if (!Number.isInteger(index) || index < 0 || index >= arr.length) {
    throw new RangeError(`index ${index} out of range 0..${arr.length - 1}`);
  }
  return arr.with(index, value);
}

Try / catch

try {
  arr.with(idx, value);
} catch (err) {
  if (err instanceof RangeError) {
    // report invalid index instead of crashing
  }
  throw err;
}

Prevention

When it happens

Trigger: `array.with(array.length, value)` (with any number of extra arguments), `object.items.with(object.items.length, value)` — the index is a static `.length` property whose object is the same expression as the receiver. `otherArray.length` or `array.length - 1` passes.

Common situations: Assuming `.with()` can grow the array, mirroring the `arr[arr.length] = v` mutation idiom; immutable-state code (React/Redux) rewriting elements; first contact with ES2023 change-by-copy methods.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/18308340568472a6. Report an issue: GitHub.