TypeScript plugin for ESLint providing comprehensive lint rules for TypeScript codebases
—
Rules that promote TypeScript and JavaScript best practices, preventing common pitfalls and anti-patterns. These rules help developers write more maintainable, performant, and error-resistant code.
Rules that encourage the use of modern JavaScript and TypeScript features.
/**
* Prefer optional chaining over chained logical ands
*/
"prefer-optional-chain": RuleModule;
/**
* Enforce nullish coalescing over logical OR
*/
"prefer-nullish-coalescing": RuleModule;
/**
* Prefer as const over literal type assertions
*/
"prefer-as-const": RuleModule;
/**
* Prefer for-of loop over traditional for loop when possible
*/
"prefer-for-of": RuleModule;
/**
* Prefer includes method over indexOf method
*/
"prefer-includes": RuleModule;
/**
* Prefer string startsWith/endsWith over substring/indexOf
*/
"prefer-string-starts-ends-with": RuleModule;
/**
* Prefer destructuring from arrays and objects
*/
"prefer-destructuring": RuleModule;Usage Examples:
// ❌ Bad - prefer-optional-chain
if (user && user.profile && user.profile.settings) {
// Access user.profile.settings
}
// ✅ Good
if (user?.profile?.settings) {
// Access user.profile.settings
}
// ❌ Bad - prefer-nullish-coalescing
const name = user.name || 'Anonymous'; // Wrong for empty string
// ✅ Good
const name = user.name ?? 'Anonymous'; // Only null/undefined
// ❌ Bad - prefer-includes
if (items.indexOf(item) !== -1) {} // Verbose
// ✅ Good
if (items.includes(item)) {} // Clear intent
// ❌ Bad - prefer-string-starts-ends-with
if (str.substring(0, 6) === 'prefix') {} // Verbose
// ✅ Good
if (str.startsWith('prefix')) {} // Clear intentRules that promote safer TypeScript patterns and discourage risky operations.
/**
* Prefer using type parameter when calling Array#reduce
*/
"prefer-reduce-type-parameter": RuleModule;
/**
* Prefer return this type for methods returning this
*/
"prefer-return-this-type": RuleModule;
/**
* Prefer using the built-in comparison function in Array.sort()
*/
"require-array-sort-compare": RuleModule;
/**
* Require that function parameters are used
*/
"no-unused-vars": RuleModule;
/**
* Disallow unnecessary parameter property assignment
*/
"no-unnecessary-parameter-property-assignment": RuleModule;
/**
* Prefer readonly arrays and tuples
*/
"prefer-readonly": RuleModule;
/**
* Prefer readonly parameter types in function declarations
*/
"prefer-readonly-parameter-types": RuleModule;Usage Examples:
// ❌ Bad - prefer-reduce-type-parameter
const result = items.reduce((acc, item) => acc + item.value, 0);
// ✅ Good
const result = items.reduce<number>((acc, item) => acc + item.value, 0);
// ❌ Bad - require-array-sort-compare
numbers.sort(); // Lexicographic sort, not numeric
// ✅ Good
numbers.sort((a, b) => a - b); // Proper numeric sort
// ❌ Bad - prefer-readonly
function processItems(items: Item[]) {} // Mutable array
// ✅ Good
function processItems(items: readonly Item[]) {} // Immutable arrayRules that promote proper error handling and exception management.
/**
* Require using Error objects as Promise rejection reasons
*/
"prefer-promise-reject-errors": RuleModule;
/**
* Enforce "throw" expressions to only throw Error objects
*/
"only-throw-error": RuleModule;
/**
* Require catch clauses to use unknown type for error
*/
"use-unknown-in-catch-callback-variable": RuleModule;
/**
* Disallow the use of eval()-like functions
*/
"no-implied-eval": RuleModule;
/**
* Disallow returning await in try/catch/finally
*/
"return-await": RuleModule;
/**
* Require async functions to have await
*/
"require-await": RuleModule;Usage Examples:
// ❌ Bad - only-throw-error
throw 'Something went wrong'; // String instead of Error
// ✅ Good
throw new Error('Something went wrong');
// ❌ Bad - use-unknown-in-catch-callback-variable
try {
riskyOperation();
} catch (error) { // error is implicitly any
console.log(error.message);
}
// ✅ Good
try {
riskyOperation();
} catch (error: unknown) {
if (error instanceof Error) {
console.log(error.message);
}
}
// ❌ Bad - prefer-promise-reject-errors
return Promise.reject('Failed'); // String rejection
// ✅ Good
return Promise.reject(new Error('Failed')); // Error objectRules that promote better function and method design patterns.
/**
* Require promise-returning functions to be async
*/
"promise-function-async": RuleModule;
/**
* Disallow functions that don't use this
*/
"class-methods-use-this": RuleModule;
/**
* Require consistent return statements
*/
"consistent-return": RuleModule;
/**
* Disallow unbound methods
*/
"unbound-method": RuleModule;
/**
* Require default parameters to be last
*/
"default-param-last": RuleModule;
/**
* Enforce maximum number of parameters
*/
"max-params": RuleModule;Usage Examples:
// ❌ Bad - promise-function-async
function fetchData() { // Should be async
return fetch('/api/data');
}
// ✅ Good
async function fetchData() {
return fetch('/api/data');
}
// ❌ Bad - unbound-method
const obj = { method() { return this.value; } };
const fn = obj.method; // Lost context
// ✅ Good
const obj = { method() { return this.value; } };
const fn = obj.method.bind(obj); // Bound contextRules that promote efficient and safe iteration patterns.
/**
* Prefer for-of loops over traditional for loops
*/
"prefer-for-of": RuleModule;
/**
* Disallow for-in loops over arrays
*/
"no-for-in-array": RuleModule;
/**
* Prefer Array.find() over filter()[0]
*/
"prefer-find": RuleModule;
/**
* Disallow function declarations in nested blocks
*/
"no-loop-func": RuleModule;Usage Examples:
// ❌ Bad - prefer-for-of
for (let i = 0; i < items.length; i++) {
console.log(items[i]);
}
// ✅ Good
for (const item of items) {
console.log(item);
}
// ❌ Bad - no-for-in-array
for (const index in array) { // for-in on array
console.log(array[index]);
}
// ✅ Good
for (const item of array) {
console.log(item);
}
// ❌ Bad - prefer-find
const user = users.filter(u => u.id === targetId)[0];
// ✅ Good
const user = users.find(u => u.id === targetId);Rules that encourage better type definition practices.
/**
* Prefer function types over interfaces with call signatures
*/
"prefer-function-type": RuleModule;
/**
* Prefer literal enum members
*/
"prefer-literal-enum-member": RuleModule;
/**
* Prefer initializing enum members
*/
"prefer-enum-initializers": RuleModule;
/**
* Require namespace keyword over module keyword
*/
"prefer-namespace-keyword": RuleModule;
/**
* Disallow empty interfaces
*/
"no-empty-interface": RuleModule;
/**
* Require consistent use of type exports
*/
"consistent-type-exports": RuleModule;Usage Examples:
// ❌ Bad - prefer-function-type
interface Handler {
(event: Event): void; // Single call signature
}
// ✅ Good
type Handler = (event: Event) => void;
// ❌ Bad - prefer-literal-enum-member
enum Status {
Active = getValue(), // Computed value
Inactive = 'inactive'
}
// ✅ Good
enum Status {
Active = 'active',
Inactive = 'inactive'
}
// ❌ Bad - no-empty-interface
interface EmptyInterface {} // No members
// ✅ Good
interface UserInterface {
name: string;
email: string;
}Rules that promote better module organization and import patterns.
/**
* Disallow unnecessary type imports
*/
"no-import-type-side-effects": RuleModule;
/**
* Require consistent type imports
*/
"consistent-type-imports": RuleModule;
/**
* Require consistent type exports
*/
"consistent-type-exports": RuleModule;
/**
* Disallow useless empty exports
*/
"no-useless-empty-export": RuleModule;
/**
* Disallow require statements except in import statements
*/
"no-require-imports": RuleModule;Usage Examples:
// ❌ Bad - consistent-type-imports
import { User, createUser } from './user'; // Mixed import
const user: User = createUser('John');
// ✅ Good
import type { User } from './user';
import { createUser } from './user';
const user: User = createUser('John');
// ❌ Bad - no-useless-empty-export
export {}; // Unnecessary empty export
// ✅ Good
export type { User };
export { createUser };Rules that help avoid performance pitfalls and promote efficient code.
/**
* Prefer regexp exec over string match for global regex
*/
"prefer-regexp-exec": RuleModule;
/**
* Disallow expressions that evaluate to NaN
*/
"no-loss-of-precision": RuleModule;
/**
* Require explicit handling of template expression types
*/
"restrict-template-expressions": RuleModule;
/**
* Require both operands of addition to be numbers or strings
*/
"restrict-plus-operands": RuleModule;
/**
* Disallow delete operator on array elements
*/
"no-array-delete": RuleModule;
/**
* Disallow dynamic delete operations
*/
"no-dynamic-delete": RuleModule;Usage Examples:
// ❌ Bad - no-array-delete
delete array[0]; // Creates hole in array
// ✅ Good
array.splice(0, 1); // Properly removes element
// ❌ Bad - restrict-plus-operands
const result = value + {}; // Unclear concatenation
// ✅ Good
const result = value + String(obj); // Explicit conversion
// ❌ Bad - no-dynamic-delete
delete obj[key]; // Dynamic property deletion
// ✅ Good
const { [key]: _, ...rest } = obj; // Destructuring removal{
"rules": {
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/prefer-as-const": "error",
"@typescript-eslint/prefer-readonly": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/only-throw-error": "error",
"@typescript-eslint/promise-function-async": "error"
}
}{
"rules": {
"@typescript-eslint/prefer-optional-chain": "warn",
"@typescript-eslint/prefer-includes": "warn",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-string-starts-ends-with": "warn",
"@typescript-eslint/consistent-type-imports": "warn"
}
}interface RuleModule {
meta: {
type: "problem" | "suggestion" | "layout";
docs: {
description: string;
recommended?: boolean | string;
requiresTypeChecking?: boolean;
};
messages: Record<string, string>;
schema: JSONSchema;
fixable?: "code" | "whitespace";
hasSuggestions?: boolean;
};
create(context: RuleContext): RuleListener;
}
interface BestPracticeRuleOptions {
allowExpressions?: boolean;
allowTypedFunctionExpressions?: boolean;
allowHigherOrderFunctions?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
allowConciseFunctionExpressionUsage?: boolean;
}
interface PreferOptionalChainOptions {
checkAny?: boolean;
checkUnknown?: boolean;
checkString?: boolean;
checkNumber?: boolean;
checkBoolean?: boolean;
checkBigInt?: boolean;
requireNullish?: boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-typescript-eslint--eslint-plugin