productive-eslint 2.0.4 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FIXES.md +1039 -0
- package/README.md +49 -13
- package/dist/index.config.d.ts +14 -4
- package/dist/index.config.js +1 -1
- package/package.json +34 -7
package/FIXES.md
ADDED
|
@@ -0,0 +1,1039 @@
|
|
|
1
|
+
# productive-eslint: Fix Guide
|
|
2
|
+
|
|
3
|
+
> Rules with autofix are omitted — run `eslint --fix` first.
|
|
4
|
+
|
|
5
|
+
## JavaScript
|
|
6
|
+
|
|
7
|
+
### default-case
|
|
8
|
+
Add a `default` case to every `switch` statement. Treat the `default` case as an unreachable scenario and throw an error (e.g., `default: throw new Error('Unknown case: ...')`).
|
|
9
|
+
|
|
10
|
+
### grouped-accessor-pairs
|
|
11
|
+
Place getter and setter for the same property next to each other. Getter should come first.
|
|
12
|
+
|
|
13
|
+
### id-length
|
|
14
|
+
Rename the identifier to be at least 2 characters long. The only allowed single-character name is `t` (for i18n). Common renames: `e` → `err`/`event`, `i` → `index`, `x`/`y` → descriptive names like `row`/`col`, `_` → `_unused`.
|
|
15
|
+
|
|
16
|
+
### no-empty-static-block
|
|
17
|
+
Remove empty `static {}` blocks from classes or add meaningful content.
|
|
18
|
+
|
|
19
|
+
### no-inner-declarations
|
|
20
|
+
Move function/variable declarations out of nested blocks to the module or function scope.
|
|
21
|
+
|
|
22
|
+
### no-object-constructor
|
|
23
|
+
Replace `new Object()` with an object literal `{}`.
|
|
24
|
+
|
|
25
|
+
### no-shadow
|
|
26
|
+
Rename the inner variable so it does not shadow the variable from an outer scope. Use a more specific name that reflects the inner variable's purpose — for example, if both scopes have `result`, rename the inner one to `mappedResult` or a domain-specific name.
|
|
27
|
+
|
|
28
|
+
### no-unused-private-class-members
|
|
29
|
+
Remove unused private class members (`#field`, `#method()`) or reference them.
|
|
30
|
+
|
|
31
|
+
### no-useless-concat
|
|
32
|
+
Merge adjacent string literals into a single string instead of concatenating.
|
|
33
|
+
```js
|
|
34
|
+
// Bad
|
|
35
|
+
const a = 'a' + 'b'
|
|
36
|
+
// Good
|
|
37
|
+
const a = 'ab'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### consistent-this
|
|
41
|
+
Prefer refactoring to use an arrow function instead, which avoids the need to capture `this` at all. If capturing `this` is truly necessary, name the variable `that` — no other name is allowed.
|
|
42
|
+
|
|
43
|
+
### for-direction
|
|
44
|
+
Fix the loop counter update so the loop can terminate. Ensure `i++` for `i < n` and `i--` for `i > n`.
|
|
45
|
+
|
|
46
|
+
### new-cap
|
|
47
|
+
Capitalize constructor function names (start with uppercase). The config sets `capIsNew: false`, so the rule primarily fires when a lowercase function is used with `new`. Rename the constructor to start with an uppercase letter, or if the function is not a constructor, remove the `new` keyword.
|
|
48
|
+
|
|
49
|
+
### no-bitwise
|
|
50
|
+
Replace bitwise operators with their intended equivalents. Common fixes: `a | b` → `a || b`, `a & b` → `a && b`, `~~x` or `x | 0` → `Math.trunc(x)`, `x << 1` → `x * 2`, `x >> 1` → `Math.floor(x / 2)`. If bitwise operations are genuinely needed (flags, binary protocols), add an `eslint-disable-next-line` comment with justification.
|
|
51
|
+
|
|
52
|
+
### no-constant-binary-expression
|
|
53
|
+
Rewrite the binary expression that always evaluates to the same result. Common causes: `a ?? 'default'` where `a` is never nullish, `obj && {}` which always evaluates to `{}`, or `x || true` which is always `true`. Identify which operand makes the expression constant and either remove the redundant check or fix the logic.
|
|
54
|
+
|
|
55
|
+
### no-constant-condition
|
|
56
|
+
Replace the constant value in `if`/`while`/ternary with a real boolean expression.
|
|
57
|
+
|
|
58
|
+
### no-constructor-return
|
|
59
|
+
Remove the `return` statement from the constructor. Constructors must not return values.
|
|
60
|
+
|
|
61
|
+
### no-invalid-this
|
|
62
|
+
Move the `this` reference inside a class method, object method, or constructor. If `this` appears in a standalone function, convert it to a class method or pass the needed context as a parameter. If the function is a callback, convert it to an arrow function (which inherits `this` from the enclosing scope).
|
|
63
|
+
|
|
64
|
+
### no-param-reassign
|
|
65
|
+
Do not reassign function parameters. Create a new variable instead. Property mutations are allowed for: `accumulator`, `ctx`, `context`, `req`, `request`, `res`, `response`, `$scope`, `staticContext`, `ref`, `model`, and names ending with `Ref`/`Model`.
|
|
66
|
+
|
|
67
|
+
### no-promise-executor-return
|
|
68
|
+
Do not return a value from a Promise executor. If the executor uses an arrow function with an implicit return (e.g., `=> resolve(1)`), wrap the body in braces. If the executor explicitly uses `return someValue`, remove the `return` keyword or replace with `resolve(someValue)`.
|
|
69
|
+
```js
|
|
70
|
+
// Bad
|
|
71
|
+
new Promise((resolve) => resolve(1))
|
|
72
|
+
// Good
|
|
73
|
+
new Promise((resolve) => { resolve(1) })
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### no-return-assign
|
|
77
|
+
Do not use assignment inside a `return` statement. Assign to a variable first, then return it.
|
|
78
|
+
|
|
79
|
+
### no-script-url
|
|
80
|
+
Do not use `javascript:` URLs. Use event handlers instead.
|
|
81
|
+
|
|
82
|
+
### no-sequences
|
|
83
|
+
Do not use the comma operator to chain expressions. Split each comma-separated expression into its own statement. In `return` statements like `return (x++, x)`, extract the side effect to a line before the return: `x++; return x;`.
|
|
84
|
+
|
|
85
|
+
### complexity
|
|
86
|
+
Reduce cyclomatic complexity to 12 or below. Each `if`, `else if`, `case`, `for`, `while`, `do`, `&&`, `||`, `??`, and ternary `?` adds 1 to complexity. To reduce: extract groups of related conditions into helper functions, replace `if/else if` chains with lookup objects/maps, use early returns to eliminate `else` branches.
|
|
87
|
+
|
|
88
|
+
### max-depth
|
|
89
|
+
Reduce block nesting depth to 2 or below. Each nested `if`, `for`, `while`, `switch`, or `try` adds one level. To reduce: invert conditions and use early `return`/`continue` (guard clauses), extract deeply nested logic into separate functions, merge consecutive `if` conditions with `&&`.
|
|
90
|
+
```js
|
|
91
|
+
// Bad (depth 3)
|
|
92
|
+
if (a) {
|
|
93
|
+
if (b) {
|
|
94
|
+
if (c) { /* ... */ }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Good
|
|
98
|
+
if (!a || !b) return
|
|
99
|
+
if (c) { /* ... */ }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### require-atomic-updates
|
|
103
|
+
Do not read a variable before `await`/`yield` and then assign to it after — another async operation may have changed its value. Fix by re-reading the variable after the `await`, using a local temporary variable, or restructuring so the read and write happen without an intervening `await`.
|
|
104
|
+
|
|
105
|
+
## TypeScript (@typescript-eslint)
|
|
106
|
+
|
|
107
|
+
### @typescript-eslint/class-literal-property-style
|
|
108
|
+
Always declare literal properties as `readonly` fields, not getters. If a getter simply returns a literal value, replace it with a `readonly` field assignment.
|
|
109
|
+
|
|
110
|
+
### @typescript-eslint/default-param-last
|
|
111
|
+
Move parameters with default values to the end of the parameter list.
|
|
112
|
+
|
|
113
|
+
### @typescript-eslint/explicit-function-return-type
|
|
114
|
+
Add an explicit return type to functions. Expressions passed as arguments are exempted (`allowExpressions: true`).
|
|
115
|
+
```ts
|
|
116
|
+
// Bad
|
|
117
|
+
const fn = () => 1
|
|
118
|
+
// Good
|
|
119
|
+
const fn = (): number => 1
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### @typescript-eslint/naming-convention
|
|
123
|
+
Rename the identifier to match the required convention. Read the ESLint error message to identify which selector was violated:
|
|
124
|
+
- `class`, `enum` — `StrictPascalCase` (e.g., `MyClass`, `MyEnum`)
|
|
125
|
+
- `enumMember` — `UPPER_CASE` (e.g., `MY_VALUE`)
|
|
126
|
+
- `interface` — `StrictPascalCase` with mandatory `I` prefix (e.g., `IMyInterface`)
|
|
127
|
+
- `typeAlias` — `StrictPascalCase` with mandatory `T` prefix (e.g., `TMyType`)
|
|
128
|
+
- `typeParameter` — `StrictPascalCase` (e.g., `TKey`, `TValue`)
|
|
129
|
+
- `variable` (const) — `strictCamelCase` for most values, `UPPER_CASE` for module-level constants
|
|
130
|
+
- `parameter` (unused) — prefix with `_`, use `camelCase` (e.g., `_unusedParam`)
|
|
131
|
+
- `objectLiteralProperty`, `import` — exempt, no rename needed
|
|
132
|
+
|
|
133
|
+
After renaming, update all references to the renamed identifier across the codebase.
|
|
134
|
+
|
|
135
|
+
### @typescript-eslint/no-base-to-string
|
|
136
|
+
Do not coerce objects to string if they don't have a meaningful `toString()`. Add a `toString()` method or serialize explicitly.
|
|
137
|
+
|
|
138
|
+
### @typescript-eslint/no-dynamic-delete
|
|
139
|
+
Replace `delete obj[key]` with `Map`/`Set` or use object rest destructuring to remove properties.
|
|
140
|
+
|
|
141
|
+
### @typescript-eslint/no-empty-object-type
|
|
142
|
+
Do not use `{}` as a type. Use `Record<string, unknown>`, `object`, or `unknown` instead. Empty interfaces are allowed (`allowInterfaces: 'always'`).
|
|
143
|
+
|
|
144
|
+
### @typescript-eslint/no-floating-promises
|
|
145
|
+
Handle every Promise: (1) add `await` before it — preferred fix inside `async` functions; (2) add `return` to propagate it to the caller; (3) append `.catch((error) => { /* handle */ })` for explicit error handling; (4) prefix with `void` only if the promise is intentionally fire-and-forget (e.g., logging, analytics). Do not use `void` as a blanket silencer.
|
|
146
|
+
|
|
147
|
+
### @typescript-eslint/no-loop-func
|
|
148
|
+
Do not define functions inside loops that reference outer mutable variables. Extract the function outside the loop.
|
|
149
|
+
|
|
150
|
+
### @typescript-eslint/no-magic-numbers
|
|
151
|
+
Extract the numeric literal into a named `const` with a descriptive name (e.g., `const MAX_RETRY_COUNT = 3`). Place it at module scope or the top of the enclosing block. Exempt (no extraction needed): `0`, `1`, `100`, `-1`, class field initializers, default parameter values, and enum values. The extracted variable must use `const` (`enforceConst: true`).
|
|
152
|
+
|
|
153
|
+
### @typescript-eslint/no-redundant-type-constituents
|
|
154
|
+
Remove type constituents that are already covered by another constituent in the union/intersection.
|
|
155
|
+
|
|
156
|
+
### @typescript-eslint/no-unnecessary-condition
|
|
157
|
+
The condition is always truthy or always falsy based on the TypeScript type. If the type is too narrow (e.g., `string` but the value can be `null` at runtime), widen the type to include the nullish case. If the condition is genuinely unnecessary (the type proves it), remove the `if` block and keep only the reachable branch's body.
|
|
158
|
+
|
|
159
|
+
### @typescript-eslint/no-unnecessary-type-conversion
|
|
160
|
+
Remove unnecessary type conversions (e.g., `String(alreadyAString)`). The value is already the correct type.
|
|
161
|
+
|
|
162
|
+
### @typescript-eslint/no-unsafe-argument
|
|
163
|
+
The argument is typed as `any`. Trace the value to its source and add a proper type annotation there. If the value comes from an untyped library, add a type assertion (e.g., `value as TExpectedType`) at the call site. If from `JSON.parse()`, validate the shape or assert the type.
|
|
164
|
+
|
|
165
|
+
### @typescript-eslint/no-unsafe-assignment
|
|
166
|
+
The right-hand side is typed as `any`. Trace the `any` to its origin — often an untyped function return, `JSON.parse()`, or a library without type definitions. Add a type annotation or assertion at the source. Adding a type annotation only on the receiving variable (e.g., `const x: string = anyValue`) will NOT fix this — the source must be typed.
|
|
167
|
+
|
|
168
|
+
### @typescript-eslint/no-unsafe-call
|
|
169
|
+
The value being called is typed as `any`. Add a type annotation to the variable or parameter that holds the function, specifying its call signature (e.g., `const handler: (event: Event) => void`). If the function comes from a third-party library, install its `@types/*` package.
|
|
170
|
+
|
|
171
|
+
### @typescript-eslint/no-unsafe-enum-comparison
|
|
172
|
+
Compare enum values only to other members of the same enum, not to raw literals.
|
|
173
|
+
|
|
174
|
+
### @typescript-eslint/no-unsafe-member-access
|
|
175
|
+
A property is being accessed on a value typed as `any`. Add a type annotation or interface to the parent object. If from `JSON.parse()` or an API response, define an interface for the shape and assert at the parse/fetch point. Type the parent object, not the accessed property.
|
|
176
|
+
|
|
177
|
+
### @typescript-eslint/no-unsafe-return
|
|
178
|
+
The function returns a value typed as `any`. Add an explicit return type to the function, then trace the `any` inside the body and type it at its source. Simply adding a return type without fixing the internal `any` will produce a type error instead of silencing this rule.
|
|
179
|
+
|
|
180
|
+
### @typescript-eslint/no-unsafe-unary-minus
|
|
181
|
+
Do not apply unary minus to `any`-typed values. Type the value as `number` first.
|
|
182
|
+
|
|
183
|
+
### @typescript-eslint/no-useless-constructor
|
|
184
|
+
Remove constructors that only call `super()` with the same arguments. They are unnecessary.
|
|
185
|
+
|
|
186
|
+
### @typescript-eslint/only-throw-error
|
|
187
|
+
Only throw `Error` objects (or subclasses). Do not throw strings or other non-Error values.
|
|
188
|
+
|
|
189
|
+
### @typescript-eslint/related-getter-setter-pairs
|
|
190
|
+
If a property has a getter, add a setter and vice versa. They should have compatible types.
|
|
191
|
+
|
|
192
|
+
### @typescript-eslint/require-array-sort-compare
|
|
193
|
+
Pass a compare function to `.sort()`. Without it, elements are sorted as strings.
|
|
194
|
+
```ts
|
|
195
|
+
// Bad
|
|
196
|
+
numbers.sort()
|
|
197
|
+
// Good
|
|
198
|
+
numbers.sort((a, b) => a - b)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### @typescript-eslint/require-await
|
|
202
|
+
This function is `async` but has no `await`. If it performs no async work, remove `async`. If the function must return a `Promise` to satisfy an interface, return `Promise.resolve(value)` explicitly. If the function should be awaiting a call but `await` is missing, add the missing `await`.
|
|
203
|
+
|
|
204
|
+
### @typescript-eslint/return-await
|
|
205
|
+
Use `return await` in `try`/`catch` blocks so exceptions are caught. Outside try/catch, return the promise directly.
|
|
206
|
+
|
|
207
|
+
### @typescript-eslint/switch-exhaustiveness-check
|
|
208
|
+
Add a `case` for every member of the union/enum, or add a `default` case.
|
|
209
|
+
|
|
210
|
+
### @typescript-eslint/unbound-method
|
|
211
|
+
Bind the method before passing it as a callback, or use an arrow function wrapper.
|
|
212
|
+
```ts
|
|
213
|
+
// Bad
|
|
214
|
+
const fn = obj.method
|
|
215
|
+
// Good
|
|
216
|
+
const fn = obj.method.bind(obj)
|
|
217
|
+
// or
|
|
218
|
+
const fn = (...args) => obj.method(...args)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### @typescript-eslint/unified-signatures
|
|
222
|
+
Merge overload signatures that differ only in one parameter into a single signature using a union type.
|
|
223
|
+
|
|
224
|
+
### @typescript-eslint/class-methods-use-this
|
|
225
|
+
This method does not reference `this`. Preferred fix: make it `static` and update all call sites from `instance.method()` to `ClassName.method()`. If the method is part of an interface contract, keep it as an instance method. Do not add a meaningless `this` reference just to satisfy the rule.
|
|
226
|
+
|
|
227
|
+
### @typescript-eslint/init-declarations
|
|
228
|
+
Initialize variables at declaration. Do not use `let x;` without an initial value.
|
|
229
|
+
|
|
230
|
+
### @typescript-eslint/max-params
|
|
231
|
+
Reduce function parameters to 3 or fewer. Group related parameters into a single options object. Define an interface for it with the `I` prefix per naming convention (e.g., `ICreateUserOptions`). Keep the 1–2 most essential parameters positional and move the rest into the options object.
|
|
232
|
+
|
|
233
|
+
### @typescript-eslint/no-extraneous-class
|
|
234
|
+
This class contains only static members. Convert each static method to a standalone exported function and each static property to an exported `const`. Remove the class and update all call sites from `ClassName.method()` to direct function imports.
|
|
235
|
+
|
|
236
|
+
### @typescript-eslint/no-invalid-void-type
|
|
237
|
+
Do not use `void` as a type except as a return type. Use `undefined` instead.
|
|
238
|
+
|
|
239
|
+
### @typescript-eslint/no-misused-promises
|
|
240
|
+
An async function is passed where a void-returning callback is expected (e.g., event handlers, `forEach`). Wrap it in a non-async wrapper: `(event) => { void handleClick(event) }`. For error handling: `(event) => { handleClick(event).catch(handleError) }`. Do not make the callback itself `async` if the caller doesn't expect a Promise return.
|
|
241
|
+
|
|
242
|
+
### @typescript-eslint/no-misused-spread
|
|
243
|
+
Do not spread a value into an incompatible context (e.g., spreading a string into an array of numbers).
|
|
244
|
+
|
|
245
|
+
### @typescript-eslint/no-mixed-enums
|
|
246
|
+
Do not mix string and number members in the same enum. Use one type consistently.
|
|
247
|
+
|
|
248
|
+
### @typescript-eslint/parameter-properties
|
|
249
|
+
Do not use TypeScript parameter properties (e.g., `constructor(private name: string)`). Instead, declare the field explicitly in the class body (`private name: string`) and assign it in the constructor (`this.name = name`).
|
|
250
|
+
|
|
251
|
+
### @typescript-eslint/prefer-enum-initializers
|
|
252
|
+
Explicitly initialize all enum members to avoid fragile implicit numbering.
|
|
253
|
+
|
|
254
|
+
### @typescript-eslint/prefer-promise-reject-errors
|
|
255
|
+
Reject promises only with `Error` objects. Do not reject with strings or `undefined`.
|
|
256
|
+
|
|
257
|
+
### @typescript-eslint/restrict-template-expressions
|
|
258
|
+
A value embedded in a template literal is not a `string`, `number`, `boolean`, or `bigint`. For objects, access a specific string property (e.g., `${error.message}` instead of `${error}`). For `undefined`/`null`, use nullish coalescing: `${value ?? 'default'}`. For arrays, use `${arr.join(', ')}`. As a last resort, call `String(value)`.
|
|
259
|
+
|
|
260
|
+
### @typescript-eslint/no-non-null-assertion
|
|
261
|
+
Remove the `!` operator. Preferred alternatives: (1) use optional chaining `obj?.prop` instead of `obj!.prop`; (2) use nullish coalescing `value ?? defaultValue` instead of `value!`; (3) add an explicit type guard (e.g., `if (value === null) throw new Error(...)`) — preferred over `!` because it fails loudly at runtime; (4) for `.find()` returning `T | undefined`, add an `if` check for the `undefined` case. Do not replace `!` with `as T` — that is equally unsafe.
|
|
262
|
+
|
|
263
|
+
### @typescript-eslint/no-explicit-any
|
|
264
|
+
Replace `any` with a proper type: (1) if the shape is known, use that type or define an interface; (2) if the value could be anything, use `unknown` and add type guards before using it; (3) if the function should work with multiple types, use a generic (`<T>`); (4) for catch clause variables, use `unknown` and narrow with `instanceof Error`; (5) for event handlers, use the specific event type (e.g., `React.ChangeEvent<HTMLInputElement>`).
|
|
265
|
+
|
|
266
|
+
## Unicorn
|
|
267
|
+
|
|
268
|
+
### unicorn/no-empty-file
|
|
269
|
+
If the file is a placeholder (e.g., an `index.ts` barrel file), add the necessary exports. If the file is truly unused, delete it and remove all imports referencing it.
|
|
270
|
+
|
|
271
|
+
### unicorn/no-unused-properties
|
|
272
|
+
Determine whether the unused property is needed downstream. If it is, add the missing reference. If not, remove the property definition. Check for typos in property names — a misspelled property is the most common cause.
|
|
273
|
+
|
|
274
|
+
### unicorn/no-useless-switch-case
|
|
275
|
+
Remove switch cases that have no unique logic and just fall through to the default.
|
|
276
|
+
|
|
277
|
+
### unicorn/prefer-blob-reading-methods
|
|
278
|
+
Use `blob.text()` or `blob.arrayBuffer()` instead of `FileReader`.
|
|
279
|
+
|
|
280
|
+
### unicorn/prefer-code-point
|
|
281
|
+
Use `String.prototype.codePointAt()` and `String.fromCodePoint()` instead of `charCodeAt()`/`fromCharCode()`.
|
|
282
|
+
|
|
283
|
+
### unicorn/prefer-default-parameters
|
|
284
|
+
Use default parameter syntax instead of manually checking for `undefined`.
|
|
285
|
+
```js
|
|
286
|
+
// Bad
|
|
287
|
+
function fn(x) { x = x || 'default' }
|
|
288
|
+
// Good
|
|
289
|
+
function fn(x = 'default') {}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### unicorn/prefer-dom-node-text-content
|
|
293
|
+
Use `node.textContent` instead of `node.innerText`.
|
|
294
|
+
|
|
295
|
+
### unicorn/prefer-event-target
|
|
296
|
+
Replace `EventEmitter` with the native `EventTarget` API: use `new EventTarget()`, `dispatchEvent(new CustomEvent('name', { detail }))`, and `addEventListener('name', handler)` instead of `emit()`/`on()`. This only applies to browser code — if the code runs in Node.js only, suppress with an inline disable comment.
|
|
297
|
+
|
|
298
|
+
### unicorn/prefer-logical-operator-over-ternary
|
|
299
|
+
Use `||` or `??` instead of a ternary that checks the same condition.
|
|
300
|
+
```js
|
|
301
|
+
// Bad
|
|
302
|
+
const x = a ? a : b
|
|
303
|
+
// Good
|
|
304
|
+
const x = a || b
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### unicorn/prefer-structured-clone
|
|
308
|
+
Use `structuredClone(obj)` instead of `JSON.parse(JSON.stringify(obj))`.
|
|
309
|
+
|
|
310
|
+
### unicorn/prefer-top-level-await
|
|
311
|
+
Replace async IIFEs (`(async () => { ... })()`) with top-level `await`. Move the awaited statements directly to module scope. This requires the file to be an ES module — if it uses `require()`/`module.exports`, first convert to ESM.
|
|
312
|
+
|
|
313
|
+
### unicorn/require-post-message-target-origin
|
|
314
|
+
Always pass a `targetOrigin` as the second argument to `postMessage()`. Use the specific origin of the target window (e.g., `'https://example.com'`). Use `'*'` only if the message contains no sensitive data.
|
|
315
|
+
|
|
316
|
+
### unicorn/consistent-destructuring
|
|
317
|
+
If you destructured some properties from an object, use the destructured variables everywhere — do not access those same properties via dot notation on the original object. Either add the missing property to the destructuring pattern, or remove it from destructuring and use dot notation throughout.
|
|
318
|
+
|
|
319
|
+
### unicorn/no-abusive-eslint-disable
|
|
320
|
+
Do not use bare `eslint-disable` without specifying rule names. Always specify which rules to disable.
|
|
321
|
+
|
|
322
|
+
### unicorn/no-accessor-recursion
|
|
323
|
+
Do not reference `this.propName` inside the getter or setter for `propName` — this causes infinite recursion. Use a private backing field (e.g., `this.#propName`) to store the underlying value, and read/write the backing field inside the accessor.
|
|
324
|
+
|
|
325
|
+
### unicorn/no-array-callback-reference
|
|
326
|
+
Do not pass function references directly to array methods. Use an inline arrow function to avoid unexpected arguments.
|
|
327
|
+
```js
|
|
328
|
+
// Bad
|
|
329
|
+
items.map(Number.parseInt)
|
|
330
|
+
// Good
|
|
331
|
+
items.map((item) => Number.parseInt(item, 10))
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### unicorn/no-magic-array-flat-depth
|
|
335
|
+
Extract the `.flat()` depth argument into a named constant when it is greater than 1.
|
|
336
|
+
|
|
337
|
+
### unicorn/no-negation-in-equality-check
|
|
338
|
+
Move the negation outside the equality check.
|
|
339
|
+
```js
|
|
340
|
+
// Bad
|
|
341
|
+
if (!a === b) {}
|
|
342
|
+
// Good
|
|
343
|
+
if (a !== b) {}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### unicorn/no-unreadable-array-destructuring
|
|
347
|
+
Avoid destructuring with many skipped elements. Access by index instead.
|
|
348
|
+
```js
|
|
349
|
+
// Bad
|
|
350
|
+
const [,,, d] = arr
|
|
351
|
+
// Good
|
|
352
|
+
const d = arr[3]
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### unicorn/no-array-method-this-argument
|
|
356
|
+
Do not pass a `thisArg` to array methods. Use an arrow function or `.bind()` instead.
|
|
357
|
+
|
|
358
|
+
### unicorn/no-await-in-promise-methods
|
|
359
|
+
Do not `await` individual promises inside `Promise.all()`, `Promise.race()`, etc. — the `await` forces sequential execution, defeating the purpose. Remove the `await` from each element.
|
|
360
|
+
```js
|
|
361
|
+
// Bad
|
|
362
|
+
await Promise.all([await fetchA(), await fetchB()])
|
|
363
|
+
// Good
|
|
364
|
+
await Promise.all([fetchA(), fetchB()])
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### unicorn/no-document-cookie
|
|
368
|
+
Do not use `document.cookie` directly. Use the Cookie Store API or a cookie utility library.
|
|
369
|
+
|
|
370
|
+
### unicorn/no-invalid-remove-event-listener
|
|
371
|
+
The function reference passed to `removeEventListener()` must be the exact same reference passed to `addEventListener()`. Store the handler in a variable at the point where `addEventListener()` is called, then pass that same variable to `removeEventListener()`.
|
|
372
|
+
```js
|
|
373
|
+
// Bad
|
|
374
|
+
el.addEventListener('click', () => handle())
|
|
375
|
+
el.removeEventListener('click', () => handle()) // Different reference!
|
|
376
|
+
// Good
|
|
377
|
+
const handler = () => handle()
|
|
378
|
+
el.addEventListener('click', handler)
|
|
379
|
+
el.removeEventListener('click', handler)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### unicorn/no-object-as-default-parameter
|
|
383
|
+
Do not use object literals as default parameter values — passing `{ a: 2 }` would lose the default for other properties. Use destructured parameters with individual defaults instead.
|
|
384
|
+
```js
|
|
385
|
+
// Bad
|
|
386
|
+
function fn(opts = { a: 1, b: 2 }) {}
|
|
387
|
+
// Good
|
|
388
|
+
function fn({ a = 1, b = 2 } = {}) {}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## SonarJS
|
|
392
|
+
|
|
393
|
+
### sonarjs/no-fallthrough
|
|
394
|
+
Add a `break`, `return`, or `throw` at the end of each `case` block. If multiple cases share the same logic, stack the `case` labels on consecutive lines with no code between them instead of using fall-through.
|
|
395
|
+
|
|
396
|
+
### sonarjs/prefer-immediate-return
|
|
397
|
+
When a variable is declared, assigned, and then immediately returned on the next line, remove the variable and return the value directly. Replace `const result = expr; return result;` with `return expr;`. Keep the variable only if its name provides important documentation of the expression's purpose.
|
|
398
|
+
|
|
399
|
+
### sonarjs/no-redundant-boolean
|
|
400
|
+
Remove redundant boolean literals. Replace `x === true` with `x`, `x === false` with `!x`, `x ? true : false` with `x`, `x ? false : true` with `!x`, `return condition ? true : false` with `return condition`.
|
|
401
|
+
|
|
402
|
+
### sonarjs/no-redundant-jump
|
|
403
|
+
Remove unnecessary `return`, `continue`, or `break` at the end of a block.
|
|
404
|
+
|
|
405
|
+
### sonarjs/non-existent-operator
|
|
406
|
+
Fix the typo: `=!` should be `!=`, `=+` should be `+=`, `=-` should be `-=`.
|
|
407
|
+
|
|
408
|
+
### sonarjs/public-static-readonly
|
|
409
|
+
Mark public static fields as `readonly` if they are never reassigned.
|
|
410
|
+
|
|
411
|
+
### sonarjs/bool-param-default
|
|
412
|
+
Provide a default value for boolean parameters.
|
|
413
|
+
|
|
414
|
+
### sonarjs/comma-or-logical-or-case
|
|
415
|
+
Each `case` in a `switch` should have its own `case` label. Do not use comma-separated values.
|
|
416
|
+
|
|
417
|
+
### sonarjs/future-reserved-words
|
|
418
|
+
Do not use future reserved words (`implements`, `interface`, `package`, etc.) as identifiers.
|
|
419
|
+
|
|
420
|
+
### sonarjs/index-of-compare-to-positive-number
|
|
421
|
+
Compare `indexOf()` result to `-1`, not to `> 0` (which misses index 0).
|
|
422
|
+
|
|
423
|
+
### sonarjs/link-with-target-blank
|
|
424
|
+
Add `rel="noopener noreferrer"` to links with `target="_blank"`.
|
|
425
|
+
|
|
426
|
+
### sonarjs/no-array-delete
|
|
427
|
+
Do not use `delete` on array elements. Use `.splice()` instead.
|
|
428
|
+
|
|
429
|
+
### sonarjs/no-duplicate-in-composite
|
|
430
|
+
Remove duplicate types in union or intersection types.
|
|
431
|
+
|
|
432
|
+
### sonarjs/no-for-in-iterable
|
|
433
|
+
Do not use `for...in` on arrays or iterables. Use `for...of` instead.
|
|
434
|
+
|
|
435
|
+
### sonarjs/no-function-declaration-in-block
|
|
436
|
+
Move function declarations out of `if`/`else`/`for`/`while` blocks.
|
|
437
|
+
|
|
438
|
+
### sonarjs/no-global-this
|
|
439
|
+
Avoid using `globalThis`. Import or declare dependencies explicitly.
|
|
440
|
+
|
|
441
|
+
### sonarjs/no-globals-shadowing
|
|
442
|
+
Do not shadow global variables (`undefined`, `NaN`, `Infinity`, etc.) with local declarations.
|
|
443
|
+
|
|
444
|
+
### sonarjs/no-identical-conditions
|
|
445
|
+
Remove or change duplicate conditions in `if`/`else if` chains.
|
|
446
|
+
|
|
447
|
+
### sonarjs/no-identical-expressions
|
|
448
|
+
Do not use the same expression on both sides of a binary operator (e.g., `a === a`, `x - x`). Determine which side is a mistake by looking at surrounding context and variable names, then fix the incorrect side. If both sides are genuinely the same and this is a no-op, remove the entire expression.
|
|
449
|
+
|
|
450
|
+
### sonarjs/no-identical-functions
|
|
451
|
+
Extract the shared logic into a single function and have the duplicates call it. Place the shared function in the nearest common scope. Name it after what it does, not where it came from.
|
|
452
|
+
|
|
453
|
+
### sonarjs/no-ignored-return
|
|
454
|
+
Use the return value of pure methods (`.map()`, `.filter()`, `.slice()`, `.trim()`, `.replace()`, etc.) — assign the result to a variable or return it. If you intended a side-effect loop, use `.forEach()` or a `for` loop instead. If you intended to mutate, use the mutating alternative (e.g., `.splice()` instead of `.slice()`).
|
|
455
|
+
|
|
456
|
+
### sonarjs/no-in-misuse
|
|
457
|
+
Use `Array.prototype.includes()` or `indexOf()` instead of `in` for arrays. `in` checks keys, not values.
|
|
458
|
+
|
|
459
|
+
### sonarjs/no-incorrect-string-concat
|
|
460
|
+
When `+` is used with a mix of strings and numbers, ensure the operation is intentional. If you intend string concatenation, convert the numeric operand with `String(num)` or use a template literal. If you intend numeric addition, ensure both operands are numbers via `Number(str)` or `parseInt()`.
|
|
461
|
+
|
|
462
|
+
### sonarjs/no-internal-api-use
|
|
463
|
+
Do not import from internal/private paths of libraries.
|
|
464
|
+
|
|
465
|
+
### sonarjs/no-misleading-array-reverse
|
|
466
|
+
`.reverse()` and `.sort()` mutate the array in-place and return the same reference. If mutation is acceptable, call the method without assigning (`arr.sort()`). If you need a new array without mutating the original, spread-copy first: `[...arr].sort()` or `[...arr].reverse()`.
|
|
467
|
+
|
|
468
|
+
### sonarjs/no-nested-template-literals
|
|
469
|
+
Extract nested template literals into variables.
|
|
470
|
+
|
|
471
|
+
### sonarjs/no-redundant-assignments
|
|
472
|
+
Remove assignments where the value is immediately overwritten.
|
|
473
|
+
|
|
474
|
+
### sonarjs/no-redundant-optional
|
|
475
|
+
Replace `?.` with `.` when the value is guaranteed to be non-nullish (the value comes from a non-optional property, was already null-checked, or the TypeScript type excludes `null`/`undefined`).
|
|
476
|
+
|
|
477
|
+
### sonarjs/no-selector-parameter
|
|
478
|
+
Do not pass CSS selectors as parameters. Pass the element directly instead.
|
|
479
|
+
|
|
480
|
+
### sonarjs/no-small-switch
|
|
481
|
+
Replace `switch` statements with fewer than 3 cases with `if`/`else`.
|
|
482
|
+
|
|
483
|
+
### sonarjs/no-try-promise
|
|
484
|
+
Synchronous `try/catch` cannot catch asynchronous rejections. Fix by making the enclosing function `async` and `await`ing the promise inside the `try` block, or remove `try/catch` and chain `.catch()` on the promise instead.
|
|
485
|
+
|
|
486
|
+
### sonarjs/no-undefined-assignment
|
|
487
|
+
Do not assign `undefined` explicitly. Use `let x;` or `delete obj.prop` instead.
|
|
488
|
+
|
|
489
|
+
### sonarjs/no-unthrown-error
|
|
490
|
+
Created `Error` objects must be thrown. Add `throw` before `new Error(...)`.
|
|
491
|
+
|
|
492
|
+
### sonarjs/no-unused-collection
|
|
493
|
+
A collection (array, Set, Map) is populated but never read. If it is needed, add the missing code that reads from it (return it, pass to another function, iterate). If it is dead code, remove the declaration and all its `.push()`/`.add()`/`.set()` calls. Check if it was meant to be returned from the function.
|
|
494
|
+
|
|
495
|
+
### sonarjs/no-unused-function-argument
|
|
496
|
+
Prefix unused parameters with `_` (e.g., `_event`). Do not remove the parameter if a later positional parameter IS used — you must keep all preceding parameters. Only remove outright if it is the last parameter and no callers pass a value for it. For callbacks with a fixed signature (event handlers, middleware), always prefix with `_` rather than removing.
|
|
497
|
+
|
|
498
|
+
### sonarjs/no-use-of-empty-return-value
|
|
499
|
+
Do not use the return value of functions that return `void`.
|
|
500
|
+
|
|
501
|
+
### sonarjs/no-useless-intersection
|
|
502
|
+
The intersection results in `never` due to incompatible constituents (e.g., `string & number`). If one type is correct, keep it and remove the `&` and the other type. If the intersection was meant to be a union, change `&` to `|`. If on object types with conflicting properties, fix the conflicting property to be compatible.
|
|
503
|
+
|
|
504
|
+
### sonarjs/object-alt-content
|
|
505
|
+
Add alternative text to `<object>` elements for accessibility.
|
|
506
|
+
|
|
507
|
+
### sonarjs/post-message
|
|
508
|
+
Specify an explicit target origin in `postMessage()` instead of `*`.
|
|
509
|
+
|
|
510
|
+
### sonarjs/prefer-promise-shorthand
|
|
511
|
+
Use `Promise.resolve()` / `Promise.reject()` instead of `new Promise((resolve) => resolve(...))`.
|
|
512
|
+
|
|
513
|
+
### sonarjs/reduce-initial-value
|
|
514
|
+
Always provide an initial value to `.reduce()`.
|
|
515
|
+
|
|
516
|
+
### sonarjs/strings-comparison
|
|
517
|
+
Use `localeCompare()` for locale-aware string comparison instead of `<` / `>`.
|
|
518
|
+
|
|
519
|
+
### sonarjs/table-header
|
|
520
|
+
Add `<th>` elements to `<table>` for accessibility.
|
|
521
|
+
|
|
522
|
+
### sonarjs/table-header-reference
|
|
523
|
+
Use the `headers` attribute on `<td>` to reference `<th>` `id`s in complex tables.
|
|
524
|
+
|
|
525
|
+
### sonarjs/expression-complexity
|
|
526
|
+
Reduce expression complexity to at most 2 logical/ternary operators per expression. Each `&&`, `||`, `??`, and `? :` counts as 1. Extract sub-expressions into descriptive `const` variables (e.g., `const isEligible = age >= 18 && hasConsent`), then combine the named variables in the final expression.
|
|
527
|
+
|
|
528
|
+
### sonarjs/no-all-duplicated-branches
|
|
529
|
+
Every branch of this `if`/`else` (or ternary/switch) has the same body, making the condition pointless. Remove the conditional entirely and keep the body as unconditional code. If the branches should differ, fix the return values — this is likely a copy-paste bug.
|
|
530
|
+
|
|
531
|
+
### sonarjs/no-async-constructor
|
|
532
|
+
Constructors cannot be `async`. Move async logic into a static `async` factory method (e.g., `static async create(): Promise<ClassName>`) that creates the instance, performs async work, and returns it. Update all `new ClassName()` call sites to `await ClassName.create()`.
|
|
533
|
+
|
|
534
|
+
### sonarjs/no-invariant-returns
|
|
535
|
+
Every code path returns the same value, making branching pointless. If the function genuinely always returns the same value, remove the branching and return directly. If branches should return different values, fix the incorrect return statements — this is likely a copy-paste bug.
|
|
536
|
+
|
|
537
|
+
### sonarjs/no-nested-switch
|
|
538
|
+
Do not nest `switch` statements. Extract the inner switch into a separate function.
|
|
539
|
+
|
|
540
|
+
### sonarjs/too-many-break-or-continue-in-loop
|
|
541
|
+
This loop has too many `break`/`continue` statements. Refactor by: extracting the loop body into a function and using early `return` instead of `continue`; replacing the loop with array methods (`.filter()`, `.find()`, `.some()`, `.every()`) where applicable; or consolidating conditions into a single guard clause at the top of the loop.
|
|
542
|
+
|
|
543
|
+
## Promise
|
|
544
|
+
|
|
545
|
+
### promise/always-return
|
|
546
|
+
Always return a value inside every `.then()` callback. If no meaningful value is needed, add `return undefined` as the last statement. Preferred: refactor the `.then()` chain to `async`/`await`.
|
|
547
|
+
|
|
548
|
+
### promise/catch-or-return
|
|
549
|
+
Every promise chain must either be returned to the calling function (so the caller handles rejection) or terminate with `.catch()`. If the promise is a standalone statement, append `.catch((error) => { /* handle */ })`. With `async`/`await`, wrap in `try`/`catch` instead.
|
|
550
|
+
|
|
551
|
+
### promise/no-multiple-resolved
|
|
552
|
+
Do not call `resolve()`/`reject()` more than once. Add early `return` after each `resolve()`/`reject()` call to prevent subsequent calls. If conditional branches each call `resolve()`/`reject()`, ensure they are mutually exclusive (use `if`/`else`, not sequential `if` blocks).
|
|
553
|
+
|
|
554
|
+
### promise/no-return-in-finally
|
|
555
|
+
Do not return values in `.finally()`. It silently swallows errors.
|
|
556
|
+
|
|
557
|
+
### promise/no-return-wrap
|
|
558
|
+
Inside `.then()`, replace `return Promise.resolve(value)` with `return value`. Inside `.catch()`, replace `return Promise.reject(error)` with `throw error`. The `.then()`/`.catch()` callbacks already wrap return values in promises automatically.
|
|
559
|
+
|
|
560
|
+
### promise/param-names
|
|
561
|
+
Name Promise executor parameters `resolve` and `reject`.
|
|
562
|
+
|
|
563
|
+
### promise/valid-params
|
|
564
|
+
Pass the correct number of arguments to Promise methods (`.then()`, `.catch()`, `.finally()`).
|
|
565
|
+
|
|
566
|
+
### promise/prefer-await-to-then
|
|
567
|
+
Refactor `.then()` chains to `async`/`await`. Make the enclosing function `async`, replace each `.then(callback)` with an `await` expression assigned to a variable, and replace `.catch(callback)` with a `try`/`catch` block.
|
|
568
|
+
|
|
569
|
+
### promise/no-nesting
|
|
570
|
+
Do not nest `.then()` inside another `.then()`. Flatten the chain by returning the inner promise from the outer `.then()` and adding a new `.then()` at the top level. Preferred: refactor the entire chain to `async`/`await`, which eliminates nesting naturally.
|
|
571
|
+
|
|
572
|
+
### promise/no-promise-in-callback
|
|
573
|
+
Do not create promises inside callback-style functions (e.g., Node.js `(err, result) => {}` callbacks). Wrap the callback-based API in a promise using `new Promise()` or `util.promisify()`, then use `async`/`await` to compose with other async operations.
|
|
574
|
+
|
|
575
|
+
## Import
|
|
576
|
+
|
|
577
|
+
### import/extensions
|
|
578
|
+
Remove `.js`, `.jsx`, `.ts`, `.tsx` extensions from import paths (e.g., `import Foo from './Foo.ts'` → `import Foo from './Foo'`). Keep extensions for non-code files (`.json`, `.css`, `.svg`) — this rule only applies to JS/TS source files.
|
|
579
|
+
|
|
580
|
+
### import/no-commonjs
|
|
581
|
+
Replace `require('...')` with `import ... from '...'`, `module.exports = ...` with `export default ...`, and `exports.foo = ...` with `export const foo = ...`. For dynamic/conditional require, use `await import('...')` instead.
|
|
582
|
+
|
|
583
|
+
### import/no-mutable-exports
|
|
584
|
+
Change exported `let`/`var` to `const`. If the value genuinely mutates, do not export it directly — export a getter function instead (e.g., `export function getFoo() { return foo; }`).
|
|
585
|
+
|
|
586
|
+
### import/no-named-default
|
|
587
|
+
Use the default import syntax instead of `import { default as Name }`.
|
|
588
|
+
|
|
589
|
+
### import/no-self-import
|
|
590
|
+
A module must not import itself. Remove the self-referencing `import` and call the local binding directly instead.
|
|
591
|
+
|
|
592
|
+
### import/export
|
|
593
|
+
Do not have multiple `export default` or duplicate named exports. If there are two default exports, keep one and convert the other to a named export. If the same name is exported twice, rename one of them. Check re-exports (`export ... from`) that may conflict with local exports.
|
|
594
|
+
|
|
595
|
+
### import/no-cycle
|
|
596
|
+
Remove circular `import` dependencies. To fix: (1) extract the shared types/logic into a new module that both files can import without a loop; (2) move one import to a dynamic `import()` at the point of use if the dependency is only needed at runtime; (3) if the cycle is caused by type imports only, switch to `import type` which is erased at runtime and does not cause circular dependency issues.
|
|
597
|
+
|
|
598
|
+
## Vue
|
|
599
|
+
|
|
600
|
+
### vue/block-lang
|
|
601
|
+
`<script>` blocks must use `lang="ts"`.
|
|
602
|
+
|
|
603
|
+
### vue/comment-directive
|
|
604
|
+
Ensure `eslint-disable` comments in `<template>` specify rule names.
|
|
605
|
+
|
|
606
|
+
### vue/component-api-style
|
|
607
|
+
Use `<script setup>` instead of Options API or non-setup Composition API.
|
|
608
|
+
|
|
609
|
+
### vue/custom-event-name-casing
|
|
610
|
+
Use `camelCase` for custom event names in `$emit()`.
|
|
611
|
+
|
|
612
|
+
### vue/define-props-declaration
|
|
613
|
+
Use type-based props declaration (`defineProps<{ ... }>()`) instead of runtime declaration.
|
|
614
|
+
|
|
615
|
+
### vue/define-props-destructuring
|
|
616
|
+
Destructure props from `defineProps()` for cleaner template references.
|
|
617
|
+
|
|
618
|
+
### vue/enforce-style-attribute
|
|
619
|
+
`<style>` blocks must use `module` attribute. Scoped styles via `<style module>`.
|
|
620
|
+
|
|
621
|
+
### vue/jsx-uses-vars
|
|
622
|
+
Variables used in JSX are marked as used. This rule prevents false `no-unused-vars` errors.
|
|
623
|
+
|
|
624
|
+
### vue/no-arrow-functions-in-watch
|
|
625
|
+
Do not use arrow functions in `watch`. Use a regular function to access component `this`.
|
|
626
|
+
|
|
627
|
+
### vue/no-deprecated-delete-set
|
|
628
|
+
Do not use `$delete` or `$set` — they are removed in Vue 3. To delete a property, use `delete obj.key`. To set a reactive property, assign directly (`obj.key = value`) — Vue 3 reactivity tracks this natively.
|
|
629
|
+
|
|
630
|
+
### vue/no-deprecated-dollar-listeners-api
|
|
631
|
+
Do not use `$listeners`. It is removed in Vue 3. Use `v-bind="$attrs"` instead.
|
|
632
|
+
|
|
633
|
+
### vue/no-deprecated-events-api
|
|
634
|
+
Do not use `$on`, `$off`, `$once`. Use an external event bus or composables.
|
|
635
|
+
|
|
636
|
+
### vue/no-deprecated-filter
|
|
637
|
+
Do not use Vue filters (`{{ value | filter }}`). Use computed properties or methods.
|
|
638
|
+
|
|
639
|
+
### vue/no-deprecated-functional-template
|
|
640
|
+
Do not use `<template functional>`. Use `<script setup>` for stateless components.
|
|
641
|
+
|
|
642
|
+
### vue/no-deprecated-html-element-is
|
|
643
|
+
Do not use `is` attribute on HTML elements. Use `<component :is="...">` instead.
|
|
644
|
+
|
|
645
|
+
### vue/no-deprecated-inline-template
|
|
646
|
+
Do not use the `inline-template` attribute. Use slots instead.
|
|
647
|
+
|
|
648
|
+
### vue/no-deprecated-model-definition
|
|
649
|
+
Use `defineModel()` or `modelValue` prop instead of deprecated `model` option.
|
|
650
|
+
|
|
651
|
+
### vue/no-deprecated-props-default-this
|
|
652
|
+
Do not use `this` in props `default` functions — `this` is `undefined` in Vue 3. Use a plain value or a factory function that derives the default without `this`. If you need another prop's value, use a computed property instead.
|
|
653
|
+
|
|
654
|
+
### vue/no-deprecated-router-link-tag-prop
|
|
655
|
+
Do not use the `tag` prop on `<router-link>`. Use the `v-slot` API.
|
|
656
|
+
|
|
657
|
+
### vue/no-deprecated-v-is
|
|
658
|
+
Do not use `v-is` directive. Use `:is` with `<component>` instead.
|
|
659
|
+
|
|
660
|
+
### vue/no-deprecated-v-on-native-modifier
|
|
661
|
+
Do not use `.native` modifier on `v-on`. In Vue 3, all events are native by default.
|
|
662
|
+
|
|
663
|
+
### vue/no-deprecated-vue-config-keycodes
|
|
664
|
+
Do not use `Vue.config.keyCodes`. Use key aliases directly (e.g., `@keyup.enter`).
|
|
665
|
+
|
|
666
|
+
### vue/no-dupe-v-else-if
|
|
667
|
+
Remove duplicate conditions in `v-if`/`v-else-if` chains.
|
|
668
|
+
|
|
669
|
+
### vue/no-duplicate-attributes
|
|
670
|
+
Do not use duplicate attributes on the same element.
|
|
671
|
+
|
|
672
|
+
### vue/no-duplicate-attr-inheritance
|
|
673
|
+
When using `inheritAttrs: false`, do not duplicate attributes that come from `$attrs`.
|
|
674
|
+
|
|
675
|
+
### vue/no-empty-pattern
|
|
676
|
+
Do not use empty destructuring patterns (e.g., `{}` or `[]`) in templates. Either destructure specific properties (e.g., `{ name }`) or remove the destructuring and use the whole object.
|
|
677
|
+
|
|
678
|
+
### vue/no-export-in-script-setup
|
|
679
|
+
Do not use `export` in `<script setup>`. Use `defineExpose()` for public API.
|
|
680
|
+
|
|
681
|
+
### vue/no-expose-after-await
|
|
682
|
+
Do not call `defineExpose()` after an `await`. Move it before any async operation.
|
|
683
|
+
|
|
684
|
+
### vue/no-irregular-whitespace
|
|
685
|
+
Remove irregular whitespace characters from templates.
|
|
686
|
+
|
|
687
|
+
### vue/no-lifecycle-after-await
|
|
688
|
+
Do not register lifecycle hooks after `await`. Move hook registration before any async operation.
|
|
689
|
+
|
|
690
|
+
### vue/no-lone-template
|
|
691
|
+
Do not use `<template>` without directives (`v-if`, `v-for`, `v-slot`). It serves no purpose.
|
|
692
|
+
|
|
693
|
+
### vue/no-loss-of-precision
|
|
694
|
+
Do not use number literals that lose precision. Use `BigInt` (e.g., `9007199254740993n`) for very large integers, or use a string representation if exact precision is needed.
|
|
695
|
+
|
|
696
|
+
### vue/no-multiple-objects-in-class
|
|
697
|
+
Do not pass multiple object expressions to `:class`. Merge them into one object.
|
|
698
|
+
|
|
699
|
+
### vue/no-multiple-slot-args
|
|
700
|
+
Slot functions must accept only a single argument (the slot props object).
|
|
701
|
+
|
|
702
|
+
### vue/no-mutating-props
|
|
703
|
+
Do not mutate props directly. Emit an event to let the parent component update the value.
|
|
704
|
+
|
|
705
|
+
### vue/no-parsing-error
|
|
706
|
+
Fix template parsing errors (unclosed tags, invalid attributes, etc.).
|
|
707
|
+
|
|
708
|
+
### vue/no-ref-object-reactivity-loss
|
|
709
|
+
Do not destructure or spread ref objects — this loses reactivity. Use `.value` or `toRefs()`.
|
|
710
|
+
|
|
711
|
+
### vue/no-reserved-component-names
|
|
712
|
+
Do not use HTML element names (e.g., `button`, `div`) or Vue built-in names (e.g., `Transition`, `KeepAlive`) as component names. Rename to something domain-specific (e.g., `AppButton`, `BaseCard`).
|
|
713
|
+
|
|
714
|
+
### vue/no-reserved-keys
|
|
715
|
+
Do not use reserved Vue instance property names (`$data`, `$props`, etc.) as component data keys.
|
|
716
|
+
|
|
717
|
+
### vue/no-reserved-props
|
|
718
|
+
Do not use reserved prop names (`key`, `ref`, `is`, `slot`).
|
|
719
|
+
|
|
720
|
+
### vue/no-restricted-block
|
|
721
|
+
Do not use restricted SFC blocks as configured by the project. Check the ESLint config for which blocks are restricted and remove or replace them accordingly.
|
|
722
|
+
|
|
723
|
+
### vue/no-restricted-syntax
|
|
724
|
+
Do not use `DebuggerStatement`, `LabeledStatement`, `WithStatement`. Do not use `reactive()` — use `ref()` instead for code consistency.
|
|
725
|
+
|
|
726
|
+
### vue/no-restricted-v-bind
|
|
727
|
+
Do not bind `v-` prefixed attributes with `v-bind`.
|
|
728
|
+
|
|
729
|
+
### vue/no-root-v-if
|
|
730
|
+
Do not use `v-if` on the root element of a template. It causes the component to be destroyed and recreated.
|
|
731
|
+
|
|
732
|
+
### vue/no-side-effects-in-computed-properties
|
|
733
|
+
Do not mutate state or trigger side effects inside computed properties. Use `watch` or `watchEffect`.
|
|
734
|
+
|
|
735
|
+
### vue/no-template-key
|
|
736
|
+
Do not put `key` on `<template>`. Place it on the child element.
|
|
737
|
+
|
|
738
|
+
### vue/no-template-shadow
|
|
739
|
+
Do not shadow variables from outer scopes in `v-for` or `v-slot`.
|
|
740
|
+
|
|
741
|
+
### vue/no-template-target-blank
|
|
742
|
+
Add `rel="noopener noreferrer"` to template links with `target="_blank"`.
|
|
743
|
+
|
|
744
|
+
### vue/no-textarea-mustache
|
|
745
|
+
Do not use mustache interpolation in `<textarea>`. Use `v-model` instead.
|
|
746
|
+
|
|
747
|
+
### vue/no-unused-components
|
|
748
|
+
Remove imported/registered components that are not used in the template.
|
|
749
|
+
|
|
750
|
+
### vue/no-unused-refs
|
|
751
|
+
Remove template refs that are never used in `<script>`.
|
|
752
|
+
|
|
753
|
+
### vue/no-unused-vars
|
|
754
|
+
Remove unused `v-for`/`v-slot` variables or prefix them with `_`.
|
|
755
|
+
|
|
756
|
+
### vue/no-use-v-else-with-v-for
|
|
757
|
+
Do not use `v-else`/`v-else-if` on an element that also has `v-for`.
|
|
758
|
+
|
|
759
|
+
### vue/no-use-v-if-with-v-for
|
|
760
|
+
Do not use `v-if` and `v-for` on the same element. Use a wrapper `<template v-for>` with `v-if` on the child.
|
|
761
|
+
|
|
762
|
+
### vue/no-useless-template-attributes
|
|
763
|
+
Remove attributes on `<template>` that have no effect (only directives work on `<template>`).
|
|
764
|
+
|
|
765
|
+
### vue/no-v-for-template-key-on-child
|
|
766
|
+
In Vue 3, place `key` on the `<template v-for>`, not on the child element.
|
|
767
|
+
|
|
768
|
+
### vue/no-watch-after-await
|
|
769
|
+
Do not register `watch` after `await`. Move the `watch` call before any async operation.
|
|
770
|
+
|
|
771
|
+
### vue/no-async-in-computed-properties
|
|
772
|
+
Do not use `async`/`await`, promises, or timers in computed properties.
|
|
773
|
+
|
|
774
|
+
### vue/no-child-content
|
|
775
|
+
Do not use `v-html`/`v-text` on elements with child content — the children will be overwritten.
|
|
776
|
+
|
|
777
|
+
### vue/no-console
|
|
778
|
+
Remove `console.log`/`console.warn`/`console.error` from Vue templates.
|
|
779
|
+
|
|
780
|
+
### vue/no-constant-condition
|
|
781
|
+
Remove constant conditions in template `v-if`/`v-show`/`v-else-if` directives.
|
|
782
|
+
|
|
783
|
+
### vue/no-sparse-arrays
|
|
784
|
+
Do not use sparse arrays (e.g., `[1, , 3]`) in templates. Use explicit `undefined` values instead (e.g., `[1, undefined, 3]`), or remove the empty slots.
|
|
785
|
+
|
|
786
|
+
### vue/no-static-inline-styles
|
|
787
|
+
Do not use inline `style` attributes. Use CSS classes or `:class`/`:style` bindings.
|
|
788
|
+
|
|
789
|
+
### vue/no-v-html
|
|
790
|
+
Do not use `v-html`. It is an XSS risk. Use template interpolation or `v-text` instead.
|
|
791
|
+
|
|
792
|
+
### vue/no-v-text
|
|
793
|
+
Do not use `v-text`. Use mustache interpolation `{{ }}` instead.
|
|
794
|
+
|
|
795
|
+
### vue/no-v-text-v-html-on-component
|
|
796
|
+
Do not use `v-text` or `v-html` on components — they overwrite slot content. Pass the content via the default slot instead (e.g., `<MyComp>content here</MyComp>`).
|
|
797
|
+
|
|
798
|
+
### vue/prefer-true-attribute-shorthand
|
|
799
|
+
Use shorthand for boolean attributes: write `disabled` instead of `:disabled="true"`.
|
|
800
|
+
|
|
801
|
+
### vue/prefer-use-template-ref
|
|
802
|
+
Use `useTemplateRef()` instead of `ref` attribute for template refs.
|
|
803
|
+
|
|
804
|
+
### vue/prop-name-casing
|
|
805
|
+
Use `camelCase` for prop names in `<script>`.
|
|
806
|
+
|
|
807
|
+
### vue/require-component-is
|
|
808
|
+
Dynamic `<component>` must have a `:is` binding.
|
|
809
|
+
|
|
810
|
+
### vue/require-explicit-emits
|
|
811
|
+
Declare all emitted events in `defineEmits()`.
|
|
812
|
+
|
|
813
|
+
### vue/require-macro-variable-name
|
|
814
|
+
Use the conventional variable name matching the macro: `const props = defineProps()`, `const emit = defineEmits()`, `const slots = defineSlots()`. Rename any non-standard variable names to these conventions.
|
|
815
|
+
|
|
816
|
+
### vue/require-render-return
|
|
817
|
+
Render functions must return a value.
|
|
818
|
+
|
|
819
|
+
### vue/require-toggle-inside-transition
|
|
820
|
+
`<transition>` content must use `v-if`, `v-show`, or dynamic components to toggle.
|
|
821
|
+
|
|
822
|
+
### vue/require-typed-ref
|
|
823
|
+
Pass a type argument to `ref()` when the initial value is `null` or `undefined`.
|
|
824
|
+
```ts
|
|
825
|
+
// Bad
|
|
826
|
+
const el = ref(null)
|
|
827
|
+
// Good
|
|
828
|
+
const el = ref<HTMLDivElement | null>(null)
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
### vue/require-v-for-key
|
|
832
|
+
Always provide a `:key` on elements using `v-for`.
|
|
833
|
+
|
|
834
|
+
### vue/slot-name-casing
|
|
835
|
+
Use `camelCase` for slot names.
|
|
836
|
+
|
|
837
|
+
### vue/use-v-on-exact
|
|
838
|
+
When an element has multiple `v-on` handlers for the same event with different modifiers (e.g., `@keyup.enter` and `@keyup`), add `.exact` to the more specific handler (e.g., `@keyup.enter.exact`) so it only fires when exactly that modifier is pressed.
|
|
839
|
+
|
|
840
|
+
### vue/valid-attribute-name
|
|
841
|
+
Use valid HTML attribute names (no spaces, quotes, equals in names).
|
|
842
|
+
|
|
843
|
+
### vue/valid-define-emits
|
|
844
|
+
`defineEmits()` must be at the top level of `<script setup>`, called only once, with either a runtime array (`defineEmits(['eventName'])`) or a type-only declaration (`defineEmits<{ (e: 'eventName'): void }>()`). Do not pass both runtime and type arguments.
|
|
845
|
+
|
|
846
|
+
### vue/valid-define-options
|
|
847
|
+
`defineOptions()` must be at the top level of `<script setup>`, called only once, with a single object literal. It must not contain `props`, `emits`, `expose`, or `slots` — those have their own macros.
|
|
848
|
+
|
|
849
|
+
### vue/valid-define-props
|
|
850
|
+
`defineProps()` must be at the top level of `<script setup>`, called only once, with either a runtime object/array or a type-only declaration (`defineProps<{ ... }>()`). Do not pass both runtime and type arguments.
|
|
851
|
+
|
|
852
|
+
### vue/valid-template-root
|
|
853
|
+
The `<template>` block must not be empty and must contain valid content. In Vue 3 multiple root elements are allowed, but the template must have at least one root node. If the template is empty, add content or remove the component.
|
|
854
|
+
|
|
855
|
+
### vue/valid-v-bind
|
|
856
|
+
Use valid `v-bind` directive syntax.
|
|
857
|
+
|
|
858
|
+
### vue/valid-v-cloak
|
|
859
|
+
Use valid `v-cloak` directive syntax.
|
|
860
|
+
|
|
861
|
+
### vue/valid-v-else
|
|
862
|
+
Use valid `v-else` directive. It must follow `v-if` or `v-else-if` and have no expression.
|
|
863
|
+
|
|
864
|
+
### vue/valid-v-else-if
|
|
865
|
+
Use valid `v-else-if` directive. It must follow `v-if` or another `v-else-if`.
|
|
866
|
+
|
|
867
|
+
### vue/valid-v-for
|
|
868
|
+
Use valid `v-for` syntax (e.g., `item of items`).
|
|
869
|
+
|
|
870
|
+
### vue/valid-v-html
|
|
871
|
+
Use valid `v-html` directive syntax with an expression.
|
|
872
|
+
|
|
873
|
+
### vue/valid-v-if
|
|
874
|
+
Use valid `v-if` directive syntax with an expression.
|
|
875
|
+
|
|
876
|
+
### vue/valid-v-is
|
|
877
|
+
Use valid `v-is` directive syntax.
|
|
878
|
+
|
|
879
|
+
### vue/valid-v-memo
|
|
880
|
+
Use valid `v-memo` directive with an array expression.
|
|
881
|
+
|
|
882
|
+
### vue/valid-v-model
|
|
883
|
+
Use valid `v-model` directive. It must be on input elements or components, with a valid expression.
|
|
884
|
+
|
|
885
|
+
### vue/valid-v-on
|
|
886
|
+
Use valid `v-on` directive syntax.
|
|
887
|
+
|
|
888
|
+
### vue/valid-v-once
|
|
889
|
+
Use valid `v-once` directive. It must have no expression or argument.
|
|
890
|
+
|
|
891
|
+
### vue/valid-v-pre
|
|
892
|
+
Use valid `v-pre` directive. It must have no expression or argument.
|
|
893
|
+
|
|
894
|
+
### vue/valid-v-show
|
|
895
|
+
Use valid `v-show` directive syntax with an expression.
|
|
896
|
+
|
|
897
|
+
### vue/valid-v-slot
|
|
898
|
+
Use valid `v-slot` directive syntax. It must be on `<template>` or a component.
|
|
899
|
+
|
|
900
|
+
### vue/valid-v-text
|
|
901
|
+
Use valid `v-text` directive syntax with an expression.
|
|
902
|
+
|
|
903
|
+
### vue/html-button-has-type
|
|
904
|
+
Add an explicit `type` attribute to `<button>` (`button`, `submit`, or `reset`).
|
|
905
|
+
|
|
906
|
+
## RxJS
|
|
907
|
+
|
|
908
|
+
### rxjs/no-compat
|
|
909
|
+
Do not import from `rxjs/Rx` or `rxjs-compat`. Use direct imports from `rxjs` and `rxjs/operators`.
|
|
910
|
+
|
|
911
|
+
### rxjs/no-create
|
|
912
|
+
Do not use `Observable.create()`. Use `new Observable()` or creation operators (`of`, `from`, etc.).
|
|
913
|
+
|
|
914
|
+
### rxjs/no-ignored-error
|
|
915
|
+
Do not call `.subscribe()` without an error handler. Either pass an observer object with an `error` callback (e.g., `.subscribe({ next: val => …, error: err => … })`) or pipe through `catchError` before subscribing.
|
|
916
|
+
|
|
917
|
+
### rxjs/no-ignored-observable
|
|
918
|
+
Do not ignore returned Observables. Either `.subscribe()` to the returned Observable, or assign it to a variable for later use. If the result is intentionally unused, pipe through `tap()` for side effects or remove the call entirely.
|
|
919
|
+
|
|
920
|
+
### rxjs/no-ignored-replay-buffer
|
|
921
|
+
Provide a `bufferSize` argument to `ReplaySubject`. The default is `Infinity`.
|
|
922
|
+
|
|
923
|
+
### rxjs/no-ignored-subscribe
|
|
924
|
+
Do not call `.subscribe()` without providing at least a next handler.
|
|
925
|
+
|
|
926
|
+
### rxjs/no-ignored-subscription
|
|
927
|
+
Assign the return value of `.subscribe()` to a variable (e.g., `const sub = obs$.subscribe(…)`) and call `sub.unsubscribe()` during cleanup (e.g., in `ngOnDestroy` or a teardown function). Alternatively, use `takeUntil(destroy$)` before `.subscribe()` to manage the lifecycle declaratively.
|
|
928
|
+
|
|
929
|
+
### rxjs/no-index
|
|
930
|
+
Do not import from `rxjs/index`. Import directly from `rxjs`.
|
|
931
|
+
|
|
932
|
+
### rxjs/no-topromise
|
|
933
|
+
Do not use `.toPromise()`. Use `firstValueFrom()` or `lastValueFrom()`.
|
|
934
|
+
|
|
935
|
+
### rxjs/no-unbound-methods
|
|
936
|
+
Bind methods before passing them as observer callbacks, or use arrow functions.
|
|
937
|
+
|
|
938
|
+
### rxjs/finnish
|
|
939
|
+
Observable variables and parameters must use the `$` suffix (`data$`, `click$`).
|
|
940
|
+
|
|
941
|
+
### rxjs/no-async-subscribe
|
|
942
|
+
Do not pass `async` functions to `.subscribe()`. Errors inside async subscribe are silently lost.
|
|
943
|
+
|
|
944
|
+
### rxjs/no-cyclic-action
|
|
945
|
+
Do not create actions that re-emit themselves, creating infinite loops in effects.
|
|
946
|
+
|
|
947
|
+
### rxjs/no-exposed-subjects
|
|
948
|
+
Do not expose `Subject` directly. Expose as `Observable` using `.asObservable()`.
|
|
949
|
+
|
|
950
|
+
### rxjs/no-ignored-notifier
|
|
951
|
+
Use the `notifications` parameter passed to `repeatWhen`/`retryWhen` to control retry/repeat timing (e.g., `retryWhen(errors => errors.pipe(delay(1000)))`). If you don't need conditional logic, use `retry({ delay: 1000 })` or `repeat({ delay: 1000 })` instead.
|
|
952
|
+
|
|
953
|
+
### rxjs/no-ignored-takewhile-value
|
|
954
|
+
Use the value parameter in `takeWhile` callbacks. If unused, use `take` instead.
|
|
955
|
+
|
|
956
|
+
### rxjs/no-redundant-notify
|
|
957
|
+
Do not call `next()` immediately before `complete()` or `error()` when the `next` value is unused downstream. Remove the redundant `next()` call and keep only `complete()` (or `error()`). If the value from `next()` is needed by subscribers, that is fine — the rule flags cases where `next()` has no effect because the stream terminates immediately after.
|
|
958
|
+
|
|
959
|
+
### rxjs/no-subclass
|
|
960
|
+
Do not subclass RxJS classes (Observable, Subject, etc.). Instead of `class MyObs extends Observable`, create a plain class that holds an Observable as a property or exposes one via a factory function that pipes creation operators and custom operators together.
|
|
961
|
+
|
|
962
|
+
### rxjs/no-subject-unsubscribe
|
|
963
|
+
Do not call `.unsubscribe()` on subjects. Unsubscribe from the subscription instead.
|
|
964
|
+
|
|
965
|
+
### rxjs/no-subject-value
|
|
966
|
+
Do not access `.value` on `BehaviorSubject`. Subscribe or use `getValue()` explicitly if necessary.
|
|
967
|
+
|
|
968
|
+
### rxjs/no-unsafe-catch
|
|
969
|
+
Place `catchError` inside `switchMap`/`mergeMap`/etc., not outside — an error outside kills the outer stream.
|
|
970
|
+
|
|
971
|
+
### rxjs/no-unsafe-first
|
|
972
|
+
Use `take(1)` inside `switchMap`/`mergeMap`/etc. instead of `first()` — `first()` errors on empty streams.
|
|
973
|
+
|
|
974
|
+
### rxjs/no-unsafe-subject-next
|
|
975
|
+
Do not call `.next()` on a subject inside an operator that may not reach it (e.g., after `takeUntil`).
|
|
976
|
+
|
|
977
|
+
### rxjs/no-unsafe-takeuntil
|
|
978
|
+
Place `takeUntil` as the last operator before `subscribe` to avoid subscription leaks.
|
|
979
|
+
|
|
980
|
+
### rxjs/suffix-subjects
|
|
981
|
+
Subject variables must use the `Subject` suffix (e.g., `clickSubject`, `dataSubject`).
|
|
982
|
+
|
|
983
|
+
### rxjs/throw-error
|
|
984
|
+
Only throw `Error` objects in `throwError()`. Do not throw strings or plain objects.
|
|
985
|
+
|
|
986
|
+
### rxjs/no-connectable
|
|
987
|
+
Do not use connectable observables. Use `share`, `shareReplay`, or `publish` operators.
|
|
988
|
+
|
|
989
|
+
### rxjs/no-nested-subscribe
|
|
990
|
+
Do not nest `.subscribe()` calls. Use `switchMap`, `mergeMap`, `concatMap`, or `exhaustMap`.
|
|
991
|
+
|
|
992
|
+
### rxjs/no-sharereplay
|
|
993
|
+
Use `shareReplay` with `{ refCount: true }` to avoid memory leaks.
|
|
994
|
+
|
|
995
|
+
### rxjs/no-subscribe-handlers
|
|
996
|
+
Use the observer object form `{ next, error, complete }` instead of positional arguments in `.subscribe()`.
|
|
997
|
+
|
|
998
|
+
### rxjs/no-unsafe-switchmap
|
|
999
|
+
Do not use `switchMap` with actions that should not be cancelled (e.g., writes/deletes). Use `concatMap` or `mergeMap`.
|
|
1000
|
+
|
|
1001
|
+
## JSDoc
|
|
1002
|
+
|
|
1003
|
+
### jsdoc/no-bad-blocks
|
|
1004
|
+
Use `/** ... */` for JSDoc comments, not `/* ... */`.
|
|
1005
|
+
|
|
1006
|
+
### jsdoc/require-jsdoc
|
|
1007
|
+
Add JSDoc comments to public APIs: type aliases, interfaces, enums, class declarations, method definitions, arrow functions at module level, object expressions, and property definitions. Analyze what each part of the code does from the perspective of public use and create a concise but comprehensive JSDoc description based on this analysis.
|
|
1008
|
+
|
|
1009
|
+
## Boundaries (FSD)
|
|
1010
|
+
|
|
1011
|
+
### boundaries/element-types
|
|
1012
|
+
Follow Feature Sliced Design import rules:
|
|
1013
|
+
- **shared** must not import from `entities`, `features`, `widgets`, `pages`, `app`
|
|
1014
|
+
- **entities** must not import from `features`, `widgets`, `pages`, `app` or other entities
|
|
1015
|
+
- **features** must not import from `widgets`, `pages`, `app` or other features
|
|
1016
|
+
- **widgets** must not import from `pages`, `app` or other widgets
|
|
1017
|
+
- **pages** must not import from `app` or other pages
|
|
1018
|
+
|
|
1019
|
+
Move the imported code to a shared layer or pass it as a dependency.
|
|
1020
|
+
|
|
1021
|
+
### boundaries/entry-point
|
|
1022
|
+
Import only from public API entry points. Non-shared layers (`entities`, `features`, `widgets`, `pages`, `app`) must be imported through `index.ts` or `index.vue`. Shared layer allows any entry point. If the required index.ts file doesn't exist - you must create it in it's respective segment (the root of an entity/feature/etc)
|
|
1023
|
+
|
|
1024
|
+
## Productive
|
|
1025
|
+
|
|
1026
|
+
### productive/no-abusive-nested-if
|
|
1027
|
+
Reduce `if` nesting to 2 levels or below. Use early returns, guard clauses, or extract nested conditions into separate functions.
|
|
1028
|
+
|
|
1029
|
+
### productive/no-else
|
|
1030
|
+
Remove `else`/`else if` blocks. Use early returns or omit the else entirely.
|
|
1031
|
+
```ts
|
|
1032
|
+
// Bad
|
|
1033
|
+
return condition ? a : b;
|
|
1034
|
+
// Good
|
|
1035
|
+
if (condition) {
|
|
1036
|
+
return a
|
|
1037
|
+
}
|
|
1038
|
+
return b
|
|
1039
|
+
```
|