no-underscore-dangle

Disallow names that start or end with an underscore

A leading or trailing underscore is a convention for "private", but it doesn't protect anything. Any code can still read and write user._id. If a member needs to be private, use a #private class member, which the language enforces.

By default the rule checks variable and function declarations and property access. It doesn't check parameters, destructured names, or method and class field names where they're defined. The name _ alone and obj.__proto__ are always allowed.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"no-underscore-dangle" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"no-underscore-dangle" = ["error", {
  allow = [], # list of strings
  allowAfterThis = false,
  allowAfterSuper = false,
  allowAfterThisConstructor = false,
  allowFunctionParams = true,
  allowInArrayDestructuring = true,
  allowInObjectDestructuring = true,
  enforceInMethodNames = false,
  enforceInClassFields = false,
}]

Examples#

example.js3 problems
const _cache = new Map();

function load_(id) {
  return user._id === id;
}
example.jsNo problems
const cache = new Map();

function load(_request, id) {
  const [_first, second] = id.split("-");
  return _.isEqual(second, user.id);
}

Options#

OptionDefaultWhat it does
allow[]Names that are never reported.
allowAfterThisfalseAllow this._name.
allowAfterSuperfalseAllow super._name.
allowAfterThisConstructorfalseAllow this.constructor._name.
allowFunctionParamstrueAllow function f(_a) {}.
allowInArrayDestructuringtrueAllow const [_a] = list.
allowInObjectDestructuringtrueAllow const { _a } = obj.
enforceInMethodNamesfalseAlso report method names, in classes and in object literals.
enforceInClassFieldsfalseAlso report class field names.

An oxlint config has one more option. allowInUsingDeclarations (default false) allows using _lock = acquire().

bunfig.toml
[lint.rules]
no-underscore-dangle = ["error", { allow = ["_id"], allowAfterThis = true }]
example.jswith { "allow": ["_id"], "allowAfterThis": true }No problems
class Store {
  find(doc) {
    return this._items.get(doc._id);
  }
}

enforceInMethodNames and enforceInClassFields also apply to private members such as #_count:

example.jswith { "enforceInMethodNames": true, "enforceInClassFields": true }3 problems
class Store {
  _items = new Map();
  #_count = 0;

  _reset() {}
}
example.jswith { "allowFunctionParams": false }1 problem
function onClick(_event) {
  close();
}

When not to use it#

Turn it off if your project uses _name for unused variables or for members that are internal by agreement.