Skip to content

DrSmile444/eslint-config-naming

Repository files navigation

eslint-config-naming logo

ESLint Config Naming

Best-practice naming conventions for TypeScript via ESLint.

DocumentationInstallUsageRule overview


Why

Naming conventions in software development offer numerous benefits:

  • Readability: Consistent naming makes code easier to read and understand, reducing cognitive load when scanning files.
  • Maintainability: Enforces best practices, improving code quality and consistency across the codebase.
  • Code Review and Collaboration: Eliminates debates on naming styles, allowing reviewers to focus on logic and speeding up the process.
  • Code Uniformity: Uniform naming promotes collective code ownership, as code looks the same regardless of who wrote it.
  • Aesthetics: Provides functional benefits and aesthetic appeal, with a visually pleasing and harmonious structure.

This config makes naming predictable and review-friendly by enforcing a coherent set of rules that scale well across:

  • Apps and Libraries
  • Frontend and Backend
  • Monorepos and Multi-team codebases

It is intentionally BYO parser setup — it ships rules only and does not assume your repo layout or parserOptions.project.


Documentation

Comprehensive documentation with detailed rule explanations and examples is available at drsmile444.github.io/eslint-config-naming.

Key resources:


At a Glance

This configuration enforces consistent naming patterns across TypeScript constructs:

Category Enforced Style Example
Types PascalCase, no I/T prefixes ApiResponse, UserData
Classes PascalCase HttpClient, DataService
Interfaces PascalCase Config, Options
Enums PascalCase (name), UPPER_CASE (members) enum Status { ACTIVE, INACTIVE }
Variables camelCase or UPPER_CASE userName, MAX_RETRIES
Booleans Prefixed with is|should|has|can|did|will isValid, hasAccess
Functions camelCase calculateTotal(), fetchData()
Class Members (public) camelCase or snake_case userCount, api_key
Class Members (protected) camelCase (no underscore) internalState
Generic Types Single letter or T-prefixed T, TData, TKey

Abbreviations and single-letter variables are restricted — only x, y, z are allowed for coordinates. Descriptive names like errorMessage and index are enforced over vague shortcuts like err, str, or i.

Code Examples

❌ Incorrect ✅ Correct
// Type prefixes
interface IApiResponse {}
type TUserData = {};

// Wrong casing
enum status {
  active,
  inactive,
}
class userService {}

// Variables
const Myvariable = 'value';
const my_constant = 'constant';
const ready = true;

// Abbreviations
const str = 'message';

// Generics
type Cache<Key, val> = Map<Key, val>;
// Clean type names
interface ApiResponse {}
type UserData = {};

// Proper casing
enum Status {
  ACTIVE,
  INACTIVE,
}
class UserService {}

// Variables
const myVariable = 'value';
const MY_CONSTANT = 'constant';
const isReady = true;

// Descriptive names
const message = 'message';

// Proper generics
type Cache<TKey, TValue> = Map<TKey, TValue>;

Note: This is a high-level overview and most rules have additional conditions and exceptions. See the Rule Matrix for complete details and examples.


Installation

1. Install peer dependencies

npm i -D eslint typescript typescript-eslint

2. Install this config

npm i -D eslint-config-naming

For other installation options, see Flat Config Usage.


Usage

Option A: Flat Config (ESLint v9/v10+)

// eslint.config.js
import tseslint from 'typescript-eslint';
import namingConfig from 'eslint-config-naming';

export default [
  // Your TS wiring (BYO parserOptions)
  {
    files: ['**/*.ts', '**/*.tsx'],
    languageOptions: {
      parser: tseslint.parser,
      parserOptions: {
        project: ['./tsconfig.json'],
        tsconfigRootDir: import.meta.dirname,
      },
    },
    plugins: {
      '@typescript-eslint': tseslint.plugin,
    },
  },

  // Naming rules
  ...namingConfig,
];

Option B: Legacy .eslintrc.*

Use the legacy shareable entry:

  • eslint-config-naming/legacy
// .eslintrc.cjs
module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: ['eslint-config-naming/legacy'],
  parserOptions: {
    project: './tsconfig.json',
  },
};

How it’s structured

Internally, the config is built as a set of small rule fragments grouped by selector:

  • memberLike rules (public/private/protected/static/readonly)
  • variables rules (default, const/global, destructured, boolean prefixes, *Component)
  • types rules (class, interface, enum, typeLike, enumMember, generics)
  • parameters rules (base, destructured)
  • functions rules (including final camelCase enforcement)
  • quoted-key escape hatch (requiresQuotes → ignored)

They are combined in a single @typescript-eslint/naming-convention rule entry list, preserving precedence.


Rule overview

This is a quick “what it enforces” list. For full details (and good/bad examples), check the Rule Matrix..

Types

  • class: PascalCase
  • interface: PascalCase and forbids I* / T* prefixes
  • typeAlias: PascalCase and forbids I* / T* prefixes
  • typeParameter: Single uppercase letters (T, U, V, K) or prefixed descriptive names (TData, KKey, VValue) or numeric subscripts (T1, T2, K1, etc.)
  • enum: PascalCase, forbids plural-ish names (like Statuses) and I*/T*
  • enumMember: UPPER_CASE

Members (memberLike)

  • public static: camelCase, PascalCase or UPPER_CASE
  • private static: camelCase, PascalCase or UPPER_CASE, no leading _
  • readonly: UPPER_CASE, camelCase, or snake_case
  • public: camelCase or snake_case
  • private: camelCase, no leading _
  • private readonly: camelCase or UPPER_CASE, no leading _
  • protected: camelCase, no leading _

Variables

  • default: camelCase or UPPER_CASE, abbreviation restrictions apply
  • const + global: allows PascalCase (in addition to camelCase/UPPER_CASE), abbreviation restrictions apply
  • destructured: allows PascalCase, camelCase, snake_case
  • booleans: camelCase with required prefix is|are|should|has|can|did|will
  • destructured booleans: no prefix requirement (interop friendly)
  • *Component: allows PascalCase if variable name ends with Component

Parameters

  • default: camelCase, abbreviation restrictions apply
  • destructured: allows PascalCase, camelCase, snake_case

Functions

  • exported/global: camelCase or PascalCase, abbreviation restrictions apply
  • default (catch-all): camelCase, abbreviation restrictions apply

Object Literals

  • objectLiteralProperty: camelCase, snake_case, PascalCase, or UPPER_CASE (flexible to support various use cases including constant objects)

Quoted members

If a name requires quotes (e.g. HTTP headers, data contracts), it's ignored.

Abbreviation Restrictions

Automatically bans common abbreviations and anti-patterns:

  • Single-letter names: i, j, k, e → use index, itemIndex, error
  • Vague abbreviations: str, num, arr, obj → use string, number, array, object
  • Intent-hiding names: data, info, tmp → use payload, metadata, temporary
  • Ambiguous abbreviations: res, req, dir, cfg → use response, request, directory, config

Well-known technical terms like id, url, api, json, html, uuid are allowed.

See Abbreviation Restrictions docs for the complete list and customization options.


Update policy

This project treats rule and packaging changes as user-facing. Before submitting a change that affects rules, exports, or packaging, please follow the project's update policy (full text in Update Policy Docs). In short, every rule-related change must include:

  • Source changes (src/) implementing the rule or selector.
  • Tests (tests/) covering both accepted and rejected examples.
  • Snippets (tests/snippets/...) for positive/negative cases where applicable.
  • Documentation updates in docs/ explaining the rule and examples.
  • README updates if usage or exports change.
  • Package metadata changes (package.json) such as version bump and export adjustments.

See docs/policies/update-policy.md for the complete checklist, versioning rules, and CI expectations.


License

MIT © 2025-Present Dmytro Vakulenko 🇺🇦