Modern TypeScript/JavaScript ESLint configuration with strict type checking and comprehensive stylistic rules. Built for ESLint 9+ flat config with full TypeScript 5.5+ support.
- β¨ ESLint 9 Flat Config - Modern configuration format with better performance
- π― Strict Type Checking - Comprehensive type-aware rules to catch errors at build time
- π¨ Built-in Formatting - Replaces Prettier with @stylistic/eslint-plugin for unified tooling
- π TypeScript 5.5+ Support - Leverages latest TypeScript features and optimizations
- π¦ Zero Config Philosophy - Sensible defaults that work out of the box
- β‘ Performance Optimized - Uses
projectService
for faster type checking - π§ Smart File Detection - Different rules for tests, configs, and type definitions
- @noneforge/eslint-config-node - Node.js backend configuration
- @noneforge/eslint-config-angular - Angular application configuration
- Node.js >=18.18.0
- ESLint >=9.22.0
- TypeScript >=5.5.0
npm install --save-dev @noneforge/eslint-config eslint typescript
or with Yarn:
yarn add --dev @noneforge/eslint-config eslint typescript
Create an eslint.config.js
file in your project root:
import config from '@noneforge/eslint-config';
export default [
...config,
// Your custom rules here
];
import config from '@noneforge/eslint-config';
export default [
...config,
{
rules: {
// Override or add custom rules
'no-console': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
}
}
];
import config from '@noneforge/eslint-config';
export default [
...config,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
project: ['./packages/*/tsconfig.json'],
}
}
}
];
Essential rules to catch common JavaScript errors:
- Syntax and Logic Errors:
no-dupe-keys
,no-unreachable
,no-unsafe-negation
- Variable Issues:
no-undef
,no-unused-vars
(TypeScript uses@typescript-eslint/no-unused-vars
with enhanced options),no-redeclare
- Async/Control Flow:
no-async-promise-executor
,no-await-in-loop
,for-direction
- Regex Safety:
no-control-regex
,no-invalid-regexp
,no-regex-spaces
Enhanced unused variables detection:
- Variables/args starting with
_
are ignored - Rest siblings in destructuring are ignored (
const { used, ...rest } = obj
) - Only checks function arguments after the last used one
- Destructured array elements starting with
_
are ignored
Strict type checking for maximum safety:
- No Any Policy:
@typescript-eslint/no-explicit-any
, allno-unsafe-*
rules - Type Assertions: Enforces consistent assertions, prevents unnecessary type operations
- Nullish Handling:
strict-boolean-expressions
with smart nullable object support - Promise/Async:
no-floating-promises
,no-misused-promises
,promise-function-async
- Type Definitions:
consistent-type-definitions
is disabled - choosetype
orinterface
based on your needs:- Use
interface
for: object shapes that can be extended, implements clauses, public APIs - Use
type
for: unions, intersections, mapped types, tuple types - Consider
interface extends
overtype &
for better performance
- Use
// β Strict boolean expressions prevent errors
if (count) { } // Error: number coercion
if (text) { } // Error: string coercion
// β
Be explicit
if (count > 0) { }
if (text !== '') { }
if (user) { } // OK: nullable object check
Automatic import organization:
- Sorting:
simple-import-sort
for consistent ordering - Type Imports: Enforces inline type imports (
import { type User }
) - No Side Effects: Prevents
import type
with side effects - Module System: No
require()
in TypeScript, ESM preferred
// β
Auto-sorted and organized
import { type Config } from './config';
import { type User, type Product } from '@/types';
import { useState } from 'react';
import path from 'node:path';
Built-in formatting via @stylistic/eslint-plugin:
- Indentation: 2 spaces, with detailed alignment rules
- Quotes: Single quotes with escape avoidance
- Semicolons: Always required
- Line Length: 120 chars (ignores URLs, strings, templates)
- Spacing: Comprehensive rules for consistency
Modern JavaScript/TypeScript patterns:
- ES6+ Features:
prefer-const
,no-var
,prefer-spread
,prefer-object-has-own
- Logical Operators:
logical-assignment-operators
(use??=
,&&=
,||=
) - String Methods:
prefer-string-starts-ends-with
over regex/indexOf - Array Methods:
prefer-find
over filter[0],prefer-includes
over indexOf - Optional Chaining:
prefer-optional-chain
over && chains
// β Old patterns
const first = array.filter(x => x.id === id)[0];
if (text.indexOf('prefix') === 0) { }
const value = obj && obj.nested && obj.nested.value;
// β
Modern patterns
const first = array.find(x => x.id === id);
if (text.startsWith('prefix')) { }
const value = obj?.nested?.value;
Consistent naming across the codebase:
- Variables:
camelCase
,PascalCase
, orUPPER_CASE
- Functions:
camelCase
orPascalCase
- Types/Interfaces:
PascalCase
- Enums:
PascalCase
- Type Parameters:
PascalCase
(generics)
Comprehensive async code handling:
- Floating Promises: Must be awaited or explicitly voided
- Async Functions: Must return promises (
promise-function-async
) - Await Usage:
require-await
ensures async functions use await - Return Await: Required in try-catch blocks for proper stack traces
// β Common async mistakes
async function bad() {
fetchData(); // floating promise
return await promise; // unnecessary outside try-catch
}
// β
Proper async handling
async function good() {
await fetchData(); // or void fetchData();
try {
return await promise; // correct in try-catch
} catch (e) {
// handle error
}
}
Smart documentation requirements:
- Exported Elements Only: JSDoc required only for explicitly exported interfaces, types, enums, functions, and arrow functions
- Library Files: Stricter requirements for files in
lib/
directories andpublic-api.ts
- all public classes, methods, and functions must be documented - Alignment: Enforces consistent JSDoc formatting
- TypeScript Integration: Disables type annotations in JSDoc
- Flexible for Internal Code: No JSDoc required for non-exported code, keeping internal implementation clean
Relaxed rules for test files (*.spec.ts
, *.test.ts
):
any
type allowed for test flexibility- No JSDoc requirements
- Console statements permitted
- Higher callback nesting limit (10 levels)
- Magic numbers allowed
- No indentation enforcement (
@stylistic/indent: 'off'
) - flexible formatting for test readability - No line length limits (
@stylistic/max-len: 'off'
) - allows long test descriptions and assertions - Floating promises allowed (
@typescript-eslint/no-floating-promises: 'off'
) - simplified async test scenarios
Smart detection for different file types:
- Config Files (
*.config.js/ts
): Allowsrequire()
, relaxed return types - Declaration Files (
*.d.ts
): Minimal rules for ambient types - JavaScript Files: Basic linting without type checking
- Library Exports (
lib/**/*.ts
,public-api.ts
): Stricter JSDoc requirements - all public classes, methods, and functions must be documented for better API documentation
// β Unnecessary type operations
const value = data as unknown as string; // double assertion
type Same<T> = T extends T ? T : never; // unnecessary constraint
if (typeof x === 'string') {
(x as string).length; // unnecessary assertion after guard
}
// β
Clean type handling
const value = data as string; // single assertion when needed
type Nullable<T> = T | null; // simple and clear
if (typeof x === 'string') {
x.length; // TypeScript knows the type
}
// β Restricted template expressions
const msg = `Count: ${someObject}`; // Error: object in template
const id = `ID: ${null}`; // Error: null without handling
// β
Allowed template usage
const msg = `Count: ${count}`; // numbers allowed
const debug = `Data: ${JSON.stringify(obj)}`; // explicit conversion
const id = `ID: ${userId ?? 'unknown'}`; // null handled
// β Missing return types
function calculate(a: number, b: number) { // Error: needs return type
return a + b;
}
// β
Explicit return types (with smart exceptions)
function calculate(a: number, b: number): number {
return a + b;
}
// β
Exceptions that don't need explicit returns
const add = (a: number, b: number) => a + b; // arrow function expressions
const handler = () => console.log('done'); // void returns
Add to .vscode/settings.json
:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.experimental.useFlatConfig": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
]
}
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint:debug": "eslint . --debug",
"type-check": "tsc --noEmit"
}
}
- Remove
.eslintrc.*
files - Create
eslint.config.js
with flat config - Update VSCode settings for flat config
- Remove Prettier (this config handles formatting)
- Use
projectService: true
for better TypeScript performance - Enable ESLint cache:
eslint . --cache
- Exclude build directories in your tsconfig.json
- Consider using
--max-warnings 0
in CI/CD
This configuration prioritizes:
- Type Safety - Catch errors at build time, not runtime
- Consistency - Unified formatting without Prettier
- Performance - Optimized for large TypeScript projects
- Developer Experience - Clear errors with practical rules
MIT
Issues and PRs welcome at GitHub