oxc-project/oxc · warning · OxcDiagnostic

Unexpected var, use let or const instead.

Error message

Unexpected var, use let or const instead.

What it means

Diagnostic from the `no-var` rule (oxlint port of ESLint no-var). `var` declarations are function-scoped and hoisted, which causes the classic loop-closure and redeclaration bugs that `let`/`const` (block-scoped) eliminate. Oxc warns on every VariableDeclaration of kind `var`, help text 'Replace var with let or const'. Ambient TypeScript declarations (`.d.ts` `declare var`) are exempted via `has_ambient_typescript_ancestor`.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_var.rs:12

use oxc_ast::{
    AstKind,
    ast::{BindingPattern, VariableDeclarationKind},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};

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

fn no_var_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Unexpected var, use let or const instead.")
        .with_help("Replace var with let or const")
        .with_label(span)
}

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

// doc: https://github.com/eslint/eslint/blob/v9.9.1/docs/src/rules/no-var.md
// code: https://github.com/eslint/eslint/blob/v9.9.1/lib/rules/no-var.js
// test: https://github.com/eslint/eslint/blob/v9.9.1/tests/lib/rules/no-var.js

declare_oxc_lint!(
    /// ### What it does
    ///
    /// ECMAScript 2015 allows programmers to create variables with block scope
    /// instead of function scope using the `let` and `const` keywords.  Block
    /// scope is common in many other programming languages and helps
    /// programmers avoid mistakes.

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Change `var` to `const` when the variable is assigned once.
  2. Change `var` to `let` when it is genuinely reassigned (loop counters, accumulators).
  3. For loop-closure patterns (`for (var i...)` with callbacks), switch to `let` so each iteration gets its own binding.
  4. If migration is too large now, scope the rule off via oxlint config `ignore` patterns or disable comments.

Example fix

// before
var total = 0;
for (var i = 0; i < items.length; i++) { total += items[i]; }

// after
let total = 0;
for (let i = 0; i < items.length; i++) { total += items[i]; }
Defensive patterns

Strategy: validation

Validate before calling

const usesVar = /^\s*(var\s)/m.test(source) || /\bfor\s*\(\s*var\b/.test(source);

Prevention

When it happens

Trigger: `var count = 0;`, `for (var i = 0; ...)`, or `var config;` in any parsed source. Runs on AstKind::VariableDeclaration where kind is Var and no ambient-TS ancestor exists.

Common situations: Legacy codebases predating ES2015; tutorials or copied snippets using var; converting a project to stricter lint configs (oxlint `correctness`/`suspicious` presets enable this rule).

Related errors


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