oxc-project/oxc · warning · OxcDiagnostic

Do not call `Object.assign()` immediately after initializing

Error message

Do not call `Object.assign()` immediately after initializing an object.

What it means

Diagnostic from the oxlint rule `unicorn/no-immediate-mutation` (Object.assign arm, category: pedantic). Declaring an object literal and immediately merging into it with the global `Object.assign(obj, ...)` is a two-step initialization; the rule wants the object built once, via object spread or literal properties. It fires only when the call directly follows the declaration of the same object-literal variable, has at least two arguments, the second is not a spread, and no argument references the variable itself.

Source

Thrown at crates/oxc_linter/src/rules/unicorn/no_immediate_mutation.rs:25

    },
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::IsGlobalReference;
use oxc_span::{GetSpan, Span};

use crate::{AstNode, context::LintContext, rule::Rule};

fn array_mutation_diagnostic(span: Span, method: &str) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(
        "Do not call `{method}()` immediately after initializing an array."
    ))
    .with_help(format!("Move the elements from `{method}()` into the array initializer."))
    .with_label(span)
}

fn object_assign_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Do not call `Object.assign()` immediately after initializing an object.")
        .with_help("Move the properties from `Object.assign()` into the object initializer.")
        .with_label(span)
}

fn object_property_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(
        "Do not assign a property immediately after initializing an object literal.",
    )
    .with_help("Move the property into the object initializer.")
    .with_label(span)
}

fn set_add_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Do not call `.add()` immediately after initializing a Set.")
        .with_help("Add the element to the Set initializer array.")
        .with_label(span)
}

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Initialize once with spread: `const config = { ...defaults, debug: true };`
  2. For computed keys use `{ ...base, [key]: value }`
  3. If the assign target is reused later and the merge must stay, restructure or suppress inline

Example fix

// before
const config = {};
Object.assign(config, defaults, { debug: true });

// after
const config = { ...defaults, debug: true };
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: `const config = {}; Object.assign(config, defaults);` or `const obj = { foo: 1 }; Object.assign(obj, { bar: 2 });` — the first argument is the identifier declared as an object literal in the immediately preceding statement. `Object.assign(obj, ...spread)` sources and self-references pass.

Common situations: Config/option merging written before spread syntax was available; older transpiled output; incremental construction leftovers in initialization paths.

Related errors


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