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.
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-eslintrules - 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"
# }