Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lint/rules/bad-array-method-on-arguments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
tags: [recommended]
---

Disallows calling array methods directly on the `arguments` object.

`arguments` is array-like but is not an `Array`, so methods such as `reduce`,
`map`, or `filter` do not exist on it and calling them throws a `TypeError`.
Convert it to a real array first with `Array.from(arguments)`, or — preferably —
use rest parameters such as `function sum(...args)`.

**Invalid:**

```typescript
function sum() {
return arguments.reduce((a, b) => a + b, 0);
}
```

**Valid:**

```typescript
function sum(...args) {
return args.reduce((a, b) => a + b, 0);
}
```
25 changes: 25 additions & 0 deletions lint/rules/bad-char-at-comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
tags: [recommended]
---

Disallows comparing the result of `String.prototype.charAt()` against a string
whose length is not 1.

`charAt` always returns a string of length 1 (a single UTF-16 code unit), or an
empty string when the index is out of range. Comparing it against a string of
length 2 or more can therefore never be true, which is almost always a bug.
Escape sequences such as `'\n'` are a single character and are fine.

**Invalid:**

```typescript
a.charAt(4) === "a2";
a.charAt(4) === "/n";
```

**Valid:**

```typescript
a.charAt(4) === "a";
a.charAt(4) === "\n";
```
24 changes: 24 additions & 0 deletions lint/rules/bad-comparison-sequence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
tags: [recommended]
---

Disallows using a comparison operator more than once in a row.

Comparison operators are binary, so a chain like `a === b === c` does not
compare all three operands. It evaluates `a === b` first and then compares that
boolean result against `c`, which is almost never what was intended. Use `&&` to
join separate comparisons instead.

**Invalid:**

```typescript
if (a === b === c) {}
if (a < b < c) {}
```

**Valid:**

```typescript
if (a === b && b === c) {}
if (a < b && b < c) {}
```
26 changes: 26 additions & 0 deletions lint/rules/bad-min-max-func.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
tags: [recommended]
---

Disallows `Math.min`/`Math.max` clamp expressions whose arguments force a
constant result.

`Math.min(Math.max(x, low), high)` is the usual way to clamp a value between two
bounds. When the bounds are swapped — for example
`Math.min(Math.max(100, x), 0)` — the expression collapses to a constant
regardless of `x`, so the clamp does nothing useful and is almost certainly a
mistake.

**Invalid:**

```typescript
Math.min(Math.max(100, x), 0);
Math.max(1000, Math.min(0, z));
```

**Valid:**

```typescript
Math.max(0, Math.min(100, x));
Math.min(1000, Math.max(0, z));
```
24 changes: 24 additions & 0 deletions lint/rules/bad-object-literal-comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
tags: [recommended]
---

Disallows comparing a value against an object or array literal.

Each object or array literal creates a brand-new reference, and references are
only ever equal to themselves. Comparisons like `x === {}` are therefore always
false and `x !== []` always true, regardless of `x`. To check whether an object
or array is empty, inspect its keys or length instead.

**Invalid:**

```typescript
if (x === {}) {}
if (arr !== []) {}
```

**Valid:**

```typescript
if (typeof x === "object" && Object.keys(x).length === 0) {}
if (Array.isArray(arr) && arr.length === 0) {}
```
24 changes: 24 additions & 0 deletions lint/rules/bad-replace-all-arg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
tags: [recommended]
---

Disallows calling `String.prototype.replaceAll()` with a regular expression that
lacks the global (`g`) flag.

`replaceAll` requires its pattern to be either a plain string or a global
regular expression. Passing a non-global regular expression throws a `TypeError`
at runtime, so this is always a bug rather than a style preference. Add the `g`
flag (or use a string pattern).

**Invalid:**

```typescript
withSpaces.replaceAll(/\s+/, ",");
```

**Valid:**

```typescript
withSpaces.replaceAll(/\s+/g, ",");
withSpaces.replaceAll(" ", ",");
```
29 changes: 29 additions & 0 deletions lint/rules/const-comparisons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
tags: [recommended]
---

Disallows redundant or logically impossible comparisons.

Combining two comparisons of the same variable against constants can produce a
condition that is always true, always false, or one where only a single
comparison actually affects the result. This usually signals a mistake — a
flipped operator, the wrong variable, or `&&` where `||` was meant. Comparing a
variable with itself (`a < a`, `a >= a`) is likewise always false or always
true.

**Invalid:**

```typescript
status_code <= 400 && status_code > 500;
status_code < 200 && status_code <= 299;
a < a;
a >= a;
```

**Valid:**

```typescript
status_code >= 400 && status_code < 500;
500 <= status_code && status_code <= 600;
a < b;
```
24 changes: 24 additions & 0 deletions lint/rules/double-comparisons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
tags: [recommended]
---

Disallows redundant pairs of comparisons that can be combined into one.

Expressions such as `x === y || x < y` repeat a comparison that a single
operator already expresses (`x <= y`). The expanded form is harder to read and
can hide a mistake, so prefer the combined operator.

**Invalid:**

```typescript
x === y || x < y;
x < y || x === y;
x === y || x > y;
```

**Valid:**

```typescript
x <= y;
x >= y;
```
34 changes: 34 additions & 0 deletions lint/rules/erasing-op.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
tags: [recommended]
---

Disallows binary operations that always evaluate to zero.

Multiplying a value by zero (`x * 0`), taking its bitwise AND with zero
(`x & 0`), or dividing zero by a value (`0 / x`) always produces `0`, no matter
what the other operand is. Such an expression is almost always a mistake — a
leftover from refactoring or a typo — because the rest of the expression has no
effect on the result. If a zero is genuinely intended, assign `0` directly.

Division is only reported when the dividend is zero (`0 / x`). `0 / 0` evaluates
to `NaN` and `x / 0` evaluates to `Infinity` (or `NaN`), so neither is reported.

**Invalid:**

```typescript
const a = x * 0;
const b = 0 * x;
const c = x & 0;
const d = 0 & x;
const e = 0 / x;
```

**Valid:**

```typescript
const a = x * 1;
const b = x / 1;
const c = 0; // assign zero directly if that is what you mean
const d = 0 / 0; // NaN, not zero
const e = x / 0; // Infinity or NaN, not zero
```
26 changes: 26 additions & 0 deletions lint/rules/missing-throw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
tags: [recommended]
---

Disallows a `new` expression whose result is immediately discarded, which
usually indicates a missing `throw`.

Writing `new Error("...")` as a statement on its own constructs the error and
throws it away without ever using it. This is almost always a forgotten `throw`
(or a missing assignment), so the intended error never propagates.

**Invalid:**

```typescript
function foo() {
new Error("something went wrong");
}
```

**Valid:**

```typescript
function foo() {
throw new Error("something went wrong");
}
```
31 changes: 31 additions & 0 deletions lint/rules/number-arg-out-of-range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
tags: [recommended]
---

Disallows out-of-range radix or precision arguments to `Number` formatting
methods.

Several `Number.prototype` methods accept a bounded integer argument and throw a
`RangeError` when it falls outside the allowed range:

- `toString(radix)` — radix must be between 2 and 36.
- `toFixed(digits)` and `toExponential(digits)` — digits must be between 0 and
20 (100 in some engines, but 0–20 is the portable range).
- `toPrecision(precision)` — precision must be between 1 and 21.

Passing a literal outside these ranges is always a runtime error.

**Invalid:**

```typescript
(42).toString(64);
(42).toString(1);
(3.14159).toPrecision(0);
```

**Valid:**

```typescript
(42).toString(16);
(3.14159).toFixed(2);
```
30 changes: 30 additions & 0 deletions lint/rules/only-used-in-recursion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
tags: [recommended]
---

Disallows function parameters that are only ever used as an argument to the
function's own recursive calls.

When a parameter is passed along unchanged on every recursive call and used
nowhere else, it has no effect on the result. It adds cognitive overhead, can
hurt performance, and often points to leftover code or a genuine bug. Remove the
parameter, or use it for something.

**Invalid:**

```typescript
function test(onlyUsedInRecursion) {
return test(onlyUsedInRecursion);
}
```

**Valid:**

```typescript
function f(a: number): number {
if (a === 0) {
return 1;
}
return f(a - 1);
}
```
24 changes: 24 additions & 0 deletions lint/rules/uninvoked-array-callback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
tags: [recommended]
---

Disallows passing a callback to an array method called directly on
`new Array(n)`.

`new Array(5)` creates an array with five _empty slots_ (holes), not five
`undefined` elements. Iteration methods such as `map`, `forEach`, and `filter`
skip holes, so the callback is never invoked and the result is another array of
empty slots. Fill the array first so it has real elements to iterate over.

**Invalid:**

```typescript
const list = new Array(5).map((_, i) => createElement(i));
```

**Valid:**

```typescript
const list = new Array(5).fill(undefined).map((_, i) => createElement(i));
const list2 = Array.from({ length: 5 }, (_, i) => createElement(i));
```
Loading