oxc-project/oxc · error

'{name}' is a function.

Error message

'{name}' is a function.

What it means

Diagnostic from oxlint's no-func-assign rule (ESLint port, eslint:recommended). It fires when an assignment target resolves to a symbol declared with a function declaration, overwriting the function binding. Reassigning function declarations is legal in sloppy mode but destroys the hoisted binding and confuses readers, so the rule reports "'{name}' is a function." with the label '{name} is re-assigned here'.

Source

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

use oxc_ast::AstKind;
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_func_assign_diagnostic(name: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("'{name}' is a function."))
        .with_help("Do not re-assign a function declared as a FunctionDeclaration.")
        .with_label(span.label(format!("{name} is re-assigned here")))
}

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

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow reassigning `function` declarations.
    ///
    /// This rule can be disabled for TypeScript code, as the TypeScript compiler
    /// enforces this check.
    ///
    /// ### Why is this bad?
    ///
    /// Overwriting/reassigning a function written as a FunctionDeclaration is often indicative of

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Use a separate variable for the new value and keep the function binding intact.
  2. If the binding must change, declare with let (let calc = function () {...}) instead of a function declaration.
  3. Rename the function or the assignment target so they stop colliding.
  4. For deliberate test monkey-patching, suppress with // oxlint-disable-next-line eslint/no-func-assign.

Example fix

// before
function format(input) {
  return input;
}
format = (input) => input.trim();

// after
function format(input) {
  return input;
}
const formatTrimmed = (input) => input.trim();
Defensive patterns

Strategy: validation

Validate before calling

const fnNames = new Set([...source.matchAll(/^\s*function\s+(\w+)/gm)].map((m) => m[1]));
const clobber = [...source.matchAll(/(\w+)\s*=[^=]/g)].some((m) => fnNames.has(m[1]));

Prevention

When it happens

Trigger: function calc() {} later followed by calc = otherFn;; compound writes like handler += wrap(handler) or handler ??= fallback; destructuring assignment [handler] = fns; where handler is a function declaration.

Common situations: Monkey-patching helpers in tests (render = mockRender); a refactor replaces a function's implementation by assigning over it instead of editing the declaration; two scripts defining the same global function name with one assigning over the other.

Related errors


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