# 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.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

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

Every option, set to its default:

```toml 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,
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 3} */}
```js
const _cache = new Map();

function load_(id) {
  return user._id === id;
}
```

Not reported:

{/* good */}
```js
const cache = new Map();

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

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `allow` | `[]` | Names that are never reported. |
| `allowAfterThis` | `false` | Allow `this._name`. |
| `allowAfterSuper` | `false` | Allow `super._name`. |
| `allowAfterThisConstructor` | `false` | Allow `this.constructor._name`. |
| `allowFunctionParams` | `true` | Allow `function f(_a) {}`. |
| `allowInArrayDestructuring` | `true` | Allow `const [_a] = list`. |
| `allowInObjectDestructuring` | `true` | Allow `const { _a } = obj`. |
| `enforceInMethodNames` | `false` | Also report method names, in classes and in object literals. |
| `enforceInClassFields` | `false` | Also report class field names. |

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

```toml bunfig.toml
[lint.rules]
no-underscore-dangle = ["error", { allow = ["_id"], allowAfterThis = true }]
```

{/* good {"options": [{"allow": ["_id"], "allowAfterThis": true}]} */}
```js
class Store {
  find(doc) {
    return this._items.get(doc._id);
  }
}
```

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

{/* bad {"options": [{"enforceInMethodNames": true, "enforceInClassFields": true}], "count": 3} */}
```js
class Store {
  _items = new Map();
  #_count = 0;

  _reset() {}
}
```

{/* bad {"options": [{"allowFunctionParams": false}]} */}
```js
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.
