javascript Best Practices July 10, 2025

ESLint Strict Config for Clean Code

A strict ESLint flat config that enforces clean code standards — no unused vars, consistent naming, limited complexity, and TypeScript best practices.

eslintlintingjavascripttypescriptconfig

Description

A production-ready ESLint flat config (eslint.config.js) that enforces clean code standards for TypeScript and JavaScript projects. Includes strict rules for complexity limits, naming conventions, import ordering, and common anti-patterns.

Features

  • Flat config format (ESLint v9+)
  • TypeScript-first with @typescript-eslint rules
  • Complexity limits — max cyclomatic complexity of 10
  • Import organization with sorted and grouped imports
  • No dead code — unused variables, unreachable code flagged as errors
  • Consistent style — naming conventions enforced

The Config

// eslint.config.js
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import importPlugin from 'eslint-plugin-import';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.strictTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
    plugins: {
      import: importPlugin,
    },
    rules: {
      // ── Complexity ──
      'complexity': ['error', { max: 10 }],
      'max-depth': ['error', 4],
      'max-lines-per-function': ['warn', { max: 50, skipBlankLines: true, skipComments: true }],
      'max-params': ['error', 4],

      // ── Clean code ──
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'no-unused-vars': 'off',
      '@typescript-eslint/no-unused-vars': ['error', {
        argsIgnorePattern: '^_',
        varsIgnorePattern: '^_',
      }],
      'no-shadow': 'off',
      '@typescript-eslint/no-shadow': 'error',
      'no-magic-numbers': ['warn', { ignore: [0, 1, -1], ignoreArrayIndexes: true }],
      'prefer-const': 'error',
      'no-var': 'error',
      'no-param-reassign': 'error',

      // ── Naming conventions ──
      '@typescript-eslint/naming-convention': [
        'error',
        { selector: 'variable', format: ['camelCase', 'UPPER_CASE', 'PascalCase'] },
        { selector: 'function', format: ['camelCase', 'PascalCase'] },
        { selector: 'typeLike', format: ['PascalCase'] },
        { selector: 'enumMember', format: ['UPPER_CASE'] },
        { selector: 'interface', format: ['PascalCase'], prefix: [] },
      ],

      // ── Imports ──
      'import/order': ['error', {
        'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
        'newlines-between': 'always',
        'alphabetize': { order: 'asc', caseInsensitive: true },
      }],
      'import/no-duplicates': 'error',

      // ── TypeScript specific ──
      '@typescript-eslint/explicit-function-return-type': ['warn', {
        allowExpressions: true,
        allowTypedFunctionExpressions: true,
      }],
      '@typescript-eslint/no-explicit-any': 'error',
      '@typescript-eslint/prefer-nullish-coalescing': 'error',
      '@typescript-eslint/prefer-optional-chain': 'error',
      '@typescript-eslint/strict-boolean-expressions': 'error',
    },
  },
  {
    ignores: ['dist/', 'node_modules/', '*.config.*'],
  },
);

Installation

npm install -D eslint typescript-eslint @eslint/js eslint-plugin-import

Usage

# Lint the project
npx eslint src/

# Auto-fix what's possible
npx eslint src/ --fix

# Add to package.json
# "scripts": {
#   "lint": "eslint src/",
#   "lint:fix": "eslint src/ --fix"
# }