oxc-project/oxc · error

Unexpected re-assignment of class {name}

Error message

Unexpected re-assignment of class {name}

What it means

Diagnostic from the oxlint rule `no-class-assign` (crates/oxc_linter/src/rules/eslint/no_class_assign.rs). It fires when the binding of a class declaration is reassigned after declaration, and emits two labels: where the class is declared and where it is re-assigned. Class bindings behave like `const` — reassigning one throws a TypeError in strict mode (which ES modules and classes always are).

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_class_assign.rs:10

use oxc_ast::{AstKind, ast::BindingIdentifier};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNode;
use oxc_span::Span;

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

fn no_class_assign_diagnostic(name: &str, decl_span: Span, assign_span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Unexpected re-assignment of class {name}"))
        .with_help("Use a different variable name instead of re-assigning the class declaration.")
        .with_labels([
            decl_span.label(format!("{name} is declared as class here")),
            assign_span.label(format!("{name} is re-assigned here")),
        ])
}

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

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow reassigning class variables.
    ///
    /// This rule can be disabled for TypeScript code, as the TypeScript compiler
    /// enforces this check.
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Use a different variable for the new value: `class A {}` then `const B = createReplacement();`.
  2. If the binding must change, declare with `let` via a class expression: `let A = class A {};`.
  3. Mutate static members instead of rebinding: `A.handler = newHandler;`.
  4. Suppress inline only if the reassignment is dead legacy code slated for removal.

Example fix

// before
class Router {}
Router = upgrade(Router); // TypeError in strict mode

// after
class Router {}
const UpgradedRouter = upgrade(Router);
Defensive patterns

Strategy: validation

Validate before calling

// Flag rebinding of a declared class name in review gates
const redecl = /^\s*class\s+(\w+)/gm;
for (const [, name] of src.matchAll(redecl)) {
  if (new RegExp(`^\\s*${name}\\s*(=[^=]|\\*=|\\+=|\+\+|--)` , 'm').test(src)) block(name);
}

Prevention

When it happens

Trigger: An AssignmentExpression (or update/compound assignment) whose target is a Reference to a SymbolId declared by a ClassDeclaration — e.g. `class A {}` later followed by `A = 1;` or `A += x`. The diagnostic carries both the decl_span and assign_span labels.

Common situations: Using the class name as a mutable namespace or registry slot (`Foo = extendedVersion`); decorator-style monkey-patching; strict-mode ESM code where this pattern throws at runtime, not just at lint time.

Related errors


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