# @typescript-eslint/naming-convention

> Enforce naming conventions for variables, functions, types, members and imports

When names follow one convention, the shape of a name tells you what it is: `UserStore` is a type, `userStore` is a value, `MAX_USERS` is a constant. This rule lets you say which shape each kind of name must have.

Without options, everything is `camelCase`, variables can also be `UPPER_CASE`, imports can also be `PascalCase`, and classes, interfaces, type aliases, enums and type parameters are `PascalCase`. One leading or trailing underscore is allowed, except on types and imports.

{/* 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]
"@typescript-eslint/naming-convention" = "error" # or "warn"
```

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

## Examples

Reported:

{/* bad {"count": 3} */}
```ts
const user_name = "ada";

function Load_user() {}

interface user_record {}
```

Not reported:

{/* good */}
```ts
const userName = "ada";
const MAX_USERS = 10;

function loadUser(_id: number) {}

interface UserRecord {}
```

## Options

The options are a list of entries. Each entry picks names with `selector` (and `modifiers`, `types`, `filter`) and says what they must look like. Your list replaces the defaults.

| Key | What it does |
| --- | --- |
| `selector` | Which kind of name, or a list of kinds. See below. |
| `format` | The allowed formats: `camelCase`, `strictCamelCase`, `PascalCase`, `StrictPascalCase`, `snake_case`, `UPPER_CASE`. `null` skips the format check. The strict ones don't allow two capitals in a row: `userId`, not `userID`. |
| `leadingUnderscore`, `trailingUnderscore` | `"forbid"`, `"allow"`, `"require"`, `"requireDouble"`, `"allowDouble"`, `"allowSingleOrDouble"`. If not set, an underscore is checked as part of the name, so `_id` isn't `camelCase`. |
| `prefix`, `suffix` | The name must start or end with one of these strings. |
| `custom` | `{ "regex": "...", "match": true }`: the name must match the pattern, or must not with `false`. |
| `filter` | A pattern, or `{ "regex", "match" }`. The entry only applies to names that pass it. |
| `modifiers` | The entry only applies to names that have all of these: `const`, `readonly`, `static`, `public`, `protected`, `private`, `#private`, `abstract`, `destructured`, `global`, `exported`, `unused`, `requiresQuotes`, `override`, `async`, `default`, `namespace`. |
| `types` | For variables, parameters, properties, getters and setters: the entry only applies to values of these types: `boolean`, `string`, `number`, `function`, `array`. This needs type information. Run `bun lint --type-aware`. Without it, the entry doesn't apply to anything. |

Selectors: `variable`, `function`, `parameter`, `parameterProperty`, `classProperty`, `objectLiteralProperty`, `typeProperty`, `classMethod`, `objectLiteralMethod`, `typeMethod`, `classicAccessor`, `autoAccessor`, `enumMember`, `class`, `interface`, `typeAlias`, `enum`, `typeParameter`, `import`.

`import` is for default and namespace imports. The names in `import { ... }` aren't checked.

Group selectors: `default` (everything), `variableLike`, `memberLike`, `typeLike`, `property`, `method`, `accessor`.

Only one entry applies to each name. A single selector wins over a group selector. Between two entries with the same selector, the one with a `filter` wins, then the one with `modifiers` or `types`.

The rule strips underscores, then the prefix and the suffix, before it checks `custom` and `format`. So with the prefix `is`, `isActive` is checked as `Active`:

{/* good {"options": [{"selector": "variable", "format": ["PascalCase"], "prefix": ["is", "has"]}]} */}
```ts
const isActive = true;
const hasAccess = false;
```

{/* bad {"options": [{"selector": "variable", "format": ["PascalCase"], "prefix": ["is", "has"]}]} */}
```ts
const active = true;
```

No `I` in front of interface names:

{/* bad {"options": [{"selector": "interface", "format": ["PascalCase"], "custom": {"regex": "^I[A-Z]", "match": false}}]} */}
```ts
interface IUser {}
```

Private members start with an underscore:

{/* bad {"options": [{"selector": "memberLike", "modifiers": ["private"], "format": ["camelCase"], "leadingUnderscore": "require"}]} */}
```ts
class Cache {
  private entries = new Map();
}
```

{/* good {"options": [{"selector": "memberLike", "modifiers": ["private"], "format": ["camelCase"], "leadingUnderscore": "require"}]} */}
```ts
class Cache {
  private _entries = new Map();
  size = 0;
}
```

A name that needs quotes never fits a format. Turn the check off for those:

{/* bad {"options": [{"selector": "default", "format": ["camelCase"]}]} */}
```ts
const headers = { "Content-Type": "text/plain" };
```

{/* good {"options": [{"selector": "default", "format": ["camelCase"]}, {"selector": "objectLiteralProperty", "modifiers": ["requiresQuotes"], "format": null}]} */}
```ts
const headers = { "Content-Type": "text/plain" };
```

Skip variables that take their name from the property they destructure:

{/* good {"options": [{"selector": "variable", "format": ["camelCase"]}, {"selector": "variable", "modifiers": ["destructured"], "format": null}]} */}
```ts
const { user_id } = await fetchUser();
```

## When not to use it

The defaults are strict about property names, which often come from an API, a database or a file format. Expect to write your own list before the rule quiets down.
