Summary
Add an allowAfterUsing option (default false) to no-underscore-dangle so that leading-underscore names are permitted specifically on using / await using declarators. The existing per-context allow-toggles (allowFunctionParams, allowInArrayDestructuring, allowInObjectDestructuring, etc.) already carve out each place where a leading-_ identifier is idiomatic; using is the modern addition that the rule doesn't yet know about.
Motivation
TC39's Explicit Resource Management proposal (now Stage 4 / ES2026, shipped in Node.js 24 and the current TypeScript releases) introduces using and await using. The common pattern is:
using _guard = enterCriticalSection();
// the binding's only job is to be disposed at scope exit —
// it's intentionally never read
doWork();
Because the binding is never read by name, users typically prefix it with _ to:
- Signal intent to readers ("this is for its side-effect on scope exit").
- Silence
no-unused-vars (ESLint and oxlint both accept a leading _ via argsIgnorePattern / varsIgnorePattern defaults or conventions).
Today this collides with no-underscore-dangle. Users have three workarounds, all unsatisfying:
- Drop the
_, which then trips no-unused-vars (TypeScript's noUnusedLocals also fires: TS6133).
- Add each name to
allow: [...] — but the list grows (_guard, _cycleGuard, _lock, _tx, _span, …) and requires global coordination for a local pattern.
- Disable the rule inline on every
using line.
None of these match the spirit of the rule's existing options, which already grant targeted escape hatches for language/runtime contexts where the underscore convention is useful (this._x via allowAfterThis, destructuring placeholders, function parameter ignores, etc.).
Proposed option
Semantics: when the binding identifier is declared via using or await using, a leading _ does not trigger the rule. Trailing _ is still rejected (matches the rest of the rule's behavior).
Implementation sketch (the rule lives at crates/oxc_linter/src/rules/eslint/no_underscore_dangle.rs): check_binding currently reaches VariableDeclarator and returns BindingContext::Plain. A branch on VariableDeclaration.kind == VariableDeclarationKind::Using | AwaitUsing can return a new BindingContext::Using (or a boolean flag), which the top-level check then consults alongside allowAfterUsing.
Prior art
Happy to open a PR if the maintainers like the direction — wanted to check interest first, since this is an extension to an ESLint rule and you may prefer to upstream it there.
Example
// with { allowAfterUsing: true }
using _cycleGuard = enterPath(onPath, value); // ✅ no warning
using __wat = foo(); // ❌ still flagged (trailing not at issue here, but leading __)
using trailing_ = foo(); // ❌ still flagged (trailing _)
// in a regular declaration — unaffected by the new option
const _temp = x; // ❌ still flagged (unless allow / other existing options apply)
Environment
- oxlint version: 1.63.0
- Rule:
eslint/no-underscore-dangle
Thank you for the excellent linter — and for the thorough option set on this rule; one more would be lovely. 🙏
Summary
Add an
allowAfterUsingoption (defaultfalse) tono-underscore-dangleso that leading-underscore names are permitted specifically onusing/await usingdeclarators. The existing per-context allow-toggles (allowFunctionParams,allowInArrayDestructuring,allowInObjectDestructuring, etc.) already carve out each place where a leading-_identifier is idiomatic;usingis the modern addition that the rule doesn't yet know about.Motivation
TC39's Explicit Resource Management proposal (now Stage 4 / ES2026, shipped in Node.js 24 and the current TypeScript releases) introduces
usingandawait using. The common pattern is:Because the binding is never read by name, users typically prefix it with
_to:no-unused-vars(ESLint and oxlint both accept a leading_viaargsIgnorePattern/varsIgnorePatterndefaults or conventions).Today this collides with
no-underscore-dangle. Users have three workarounds, all unsatisfying:_, which then tripsno-unused-vars(TypeScript'snoUnusedLocalsalso fires:TS6133).allow: [...]— but the list grows (_guard,_cycleGuard,_lock,_tx,_span, …) and requires global coordination for a local pattern.usingline.None of these match the spirit of the rule's existing options, which already grant targeted escape hatches for language/runtime contexts where the underscore convention is useful (
this._xviaallowAfterThis, destructuring placeholders, function parameter ignores, etc.).Proposed option
{ "rules": { "no-underscore-dangle": ["error", { "allowAfterUsing": true // default: false }] } }Semantics: when the binding identifier is declared via
usingorawait using, a leading_does not trigger the rule. Trailing_is still rejected (matches the rest of the rule's behavior).Implementation sketch (the rule lives at
crates/oxc_linter/src/rules/eslint/no_underscore_dangle.rs):check_bindingcurrently reachesVariableDeclaratorand returnsBindingContext::Plain. A branch onVariableDeclaration.kind == VariableDeclarationKind::Using | AwaitUsingcan return a newBindingContext::Using(or a boolean flag), which the top-level check then consults alongsideallowAfterUsing.Prior art
no-underscore-danglewas last extended forallowFunctionParams(refactor(linter): derive inmpls forPartialEq,Eqover manual ones #13828) andallowInObjectDestructuring— both narrow opt-ins for specific syntactic positions.allowAfterUsingfollows the same shape.allowAfterThis/allowAfterSuperfor grep-ability.Happy to open a PR if the maintainers like the direction — wanted to check interest first, since this is an extension to an ESLint rule and you may prefer to upstream it there.
Example
Environment
eslint/no-underscore-dangleThank you for the excellent linter — and for the thorough option set on this rule; one more would be lovely. 🙏