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
- Change `var` to `const` when the variable is assigned once.
- Change `var` to `let` when it is genuinely reassigned (loop counters, accumulators).
- For loop-closure patterns (`for (var i...)` with callbacks), switch to `let` so each iteration gets its own binding.
- 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
- Default to `const`; switch to `let` only on true reassignment.
- When modernizing legacy files, convert `var` first, then re-lint.
- Keep ambient `.d.ts` declare-var code out of lint scope; the rule already exempts it.
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
- '{name}' is already defined.
- '{name}' is already declared in the upper scope.
- Avoid unnecessary use of .{name}()
- Unexpected `void` operator
- Unexpected use of `with` statement.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/62a5094a35f5499a.
Report an issue: GitHub.