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
- Initialize once with spread: `const config = { ...defaults, debug: true };`
- For computed keys use `{ ...base, [key]: value }`
- 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
- Prefer object spread over Object.assign for building new objects
- Reserve Object.assign for patching existing targets that cannot be rebuilt
- Treat init-then-assign pairs as a refactor signal in review
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
- Do not assign a property immediately after initializing an o
- Object keys should be sorted
- Do not call `{method}()` immediately after initializing an a
- `VirtualFree` failed during cleanup: {err}
- Tried to get an allocator from an empty `FixedSizeAllocatorP
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/adb123de9b56097e.
Report an issue: GitHub.