@codelaw/rules-ts 0.0.0-stage → 0.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.
@@ -0,0 +1,54 @@
1
+ ---
2
+ id: ts/no-require-imports
3
+ title: "No require() calls"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "an import may need the module's default or named exports chosen by hand"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/no-require-imports]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ Modules are loaded with `import`, not `require()`.
13
+
14
+ **Why:** `require()` is untyped and invisible to TypeScript's module checks.
15
+
16
+ ```codelaw
17
+ match:
18
+ pattern: require($$$ARGS)
19
+ message: "Use `import` instead of `require()`"
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Replace the call with an `import` of the names the code uses.
25
+
26
+ ## Examples
27
+
28
+ ### TypeScript
29
+
30
+ #### Don't
31
+
32
+ ```ts
33
+ const fs = require("node:fs");
34
+ ```
35
+
36
+ #### Do
37
+
38
+ ```ts
39
+ import fs from "node:fs";
40
+ ```
41
+
42
+ ### TSX
43
+
44
+ #### Don't
45
+
46
+ ```tsx
47
+ const fs = require("node:fs");
48
+ ```
49
+
50
+ #### Do
51
+
52
+ ```tsx
53
+ import fs from "node:fs";
54
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ id: ts/no-this-alias
3
+ title: "No aliasing this to a variable"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "the callbacks that use the alias must become arrow functions by hand"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/no-this-alias]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ `this` is not stored in a variable such as `self` or `that`; destructuring it is fine.
13
+
14
+ **Why:** Arrow functions keep the outer `this`, so an alias only adds a name to keep track of.
15
+
16
+ ```codelaw
17
+ match:
18
+ kind: variable_declarator
19
+ all:
20
+ - has: { field: name, kind: identifier }
21
+ - has: { field: value, kind: this }
22
+ message: "Use an arrow function instead of aliasing `this`"
23
+ ```
24
+
25
+ ## How to fix
26
+
27
+ 1. Turn the callbacks that use the alias into arrow functions.
28
+ 2. Use `this` directly and remove the alias.
29
+
30
+ ## Examples
31
+
32
+ ### TypeScript
33
+
34
+ #### Don't
35
+
36
+ ```ts
37
+ const self = this;
38
+ button.onclick = function () {
39
+ self.save();
40
+ };
41
+ ```
42
+
43
+ #### Do
44
+
45
+ ```ts
46
+ button.onclick = () => {
47
+ this.save();
48
+ };
49
+ ```
50
+
51
+ ### TSX
52
+
53
+ #### Don't
54
+
55
+ ```tsx
56
+ const self = this;
57
+ button.onclick = function () {
58
+ self.save();
59
+ };
60
+ ```
61
+
62
+ #### Do
63
+
64
+ ```tsx
65
+ button.onclick = () => {
66
+ this.save();
67
+ };
68
+ ```
@@ -0,0 +1,64 @@
1
+ ---
2
+ id: ts/no-unnecessary-type-constraint
3
+ title: "No extends any or extends unknown on a type parameter"
4
+ languages: [typescript, tsx]
5
+ fix: suggest
6
+ fix_reason: "in a .tsx arrow function `<T>` alone parses as JSX and needs `<T,>`"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/no-unnecessary-type-constraint]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A type parameter isn't constrained to `any` or `unknown`.
13
+
14
+ **Why:** Every type extends both, so the constraint says nothing.
15
+
16
+ ```codelaw
17
+ match:
18
+ kind: type_parameter
19
+ all:
20
+ - has: { field: name, pattern: $NAME }
21
+ - has:
22
+ field: constraint
23
+ has: { kind: predefined_type, regex: ^(any|unknown)$ }
24
+ message: "Every type already extends `any` and `unknown`; drop the constraint"
25
+ fix: "$NAME"
26
+ ```
27
+
28
+ ## Examples
29
+
30
+ ### TypeScript
31
+
32
+ #### Don't
33
+
34
+ ```ts
35
+ function id<T extends unknown>(x: T) {
36
+ return x;
37
+ }
38
+ ```
39
+
40
+ #### Do
41
+
42
+ ```ts
43
+ function id<T>(x: T) {
44
+ return x;
45
+ }
46
+ ```
47
+
48
+ ### TSX
49
+
50
+ #### Don't
51
+
52
+ ```tsx
53
+ function id<T extends unknown>(x: T) {
54
+ return x;
55
+ }
56
+ ```
57
+
58
+ #### Do
59
+
60
+ ```tsx
61
+ function id<T>(x: T) {
62
+ return x;
63
+ }
64
+ ```
@@ -0,0 +1,73 @@
1
+ ---
2
+ id: ts/no-unsafe-declaration-merging
3
+ title: "No interface that merges with a class of the same name"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "whether to rename or to move the members into the class needs the author"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/no-unsafe-declaration-merging]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ An interface doesn't share its name with a class in the same scope.
13
+
14
+ **Why:** The merged interface adds members to the class's type that the class never initialises, and
15
+ the compiler can't tell.
16
+
17
+ ```codelaw
18
+ native: ts/no-unsafe-declaration-merging
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Move the interface's members into the class, or rename the interface.
24
+
25
+ ## Examples
26
+
27
+ ### TypeScript
28
+
29
+ #### Don't
30
+
31
+ ```ts
32
+ interface Point {
33
+ z: number;
34
+ }
35
+ class Point {
36
+ x = 0;
37
+ }
38
+ ```
39
+
40
+ #### Do
41
+
42
+ ```ts
43
+ interface PointLike {
44
+ z: number;
45
+ }
46
+ class Point {
47
+ x = 0;
48
+ }
49
+ ```
50
+
51
+ ### TSX
52
+
53
+ #### Don't
54
+
55
+ ```tsx
56
+ interface Point {
57
+ z: number;
58
+ }
59
+ class Point {
60
+ x = 0;
61
+ }
62
+ ```
63
+
64
+ #### Do
65
+
66
+ ```tsx
67
+ interface PointLike {
68
+ z: number;
69
+ }
70
+ class Point {
71
+ x = 0;
72
+ }
73
+ ```
@@ -0,0 +1,57 @@
1
+ ---
2
+ id: ts/no-unsafe-function-type
3
+ title: "No Function type"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "the right signature needs the author"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/no-unsafe-function-type]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ The built-in `Function` type is not used as a type.
13
+
14
+ **Why:** `Function` accepts any function and its calls are unchecked, like `any` for functions.
15
+
16
+ ```codelaw
17
+ match:
18
+ kind: type_identifier
19
+ regex: ^Function$
20
+ where:
21
+ $$MATCH: builtin
22
+ message: "`Function` accepts any function and calls it unchecked; write the signature"
23
+ ```
24
+
25
+ ## How to fix
26
+
27
+ 1. Write the function's real signature, e.g. `(event: Event) => void`.
28
+
29
+ ## Examples
30
+
31
+ ### TypeScript
32
+
33
+ #### Don't
34
+
35
+ ```ts
36
+ let handler: Function;
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```ts
42
+ let handler: (event: Event) => void;
43
+ ```
44
+
45
+ ### TSX
46
+
47
+ #### Don't
48
+
49
+ ```tsx
50
+ let handler: Function;
51
+ ```
52
+
53
+ #### Do
54
+
55
+ ```tsx
56
+ let handler: (event: Event) => void;
57
+ ```
@@ -0,0 +1,61 @@
1
+ ---
2
+ id: ts/no-unused-expressions
3
+ title: "No expression statements that do nothing"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "whether a call, an assignment or nothing was meant needs the author"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/no-unused-expressions, eslint/no-unused-expressions]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ Every expression statement does something: a call, an assignment, an update, `await`, `yield`,
13
+ `delete` or `void`. Directives such as `"use strict"` are allowed.
14
+
15
+ **Why:** An expression whose value is thrown away is usually a forgotten call or assignment.
16
+
17
+ ```codelaw
18
+ native: ts/no-unused-expressions
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Add the call or assignment that was meant, or remove the statement.
24
+
25
+ ## Examples
26
+
27
+ ### TypeScript
28
+
29
+ #### Don't
30
+
31
+ ```ts
32
+ function close(conn: Connection) {
33
+ conn.close;
34
+ }
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```ts
40
+ function close(conn: Connection) {
41
+ conn.close();
42
+ }
43
+ ```
44
+
45
+ ### TSX
46
+
47
+ #### Don't
48
+
49
+ ```tsx
50
+ function close(conn: Connection) {
51
+ conn.close;
52
+ }
53
+ ```
54
+
55
+ #### Do
56
+
57
+ ```tsx
58
+ function close(conn: Connection) {
59
+ conn.close();
60
+ }
61
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ id: ts/no-unused-vars
3
+ title: "Every declared name is used"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "removing a declaration can drop the side effects of its initialiser"
7
+ stability: preview
8
+ options:
9
+ vars: { type: string, default: all }
10
+ args: { type: string, default: after-used }
11
+ caughtErrors: { type: string, default: all }
12
+ ignoreRestSiblings: { type: boolean, default: false }
13
+ varsIgnorePattern: { type: string }
14
+ argsIgnorePattern: { type: string }
15
+ caughtErrorsIgnorePattern: { type: string }
16
+ destructuredArrayIgnorePattern: { type: string }
17
+ ported_from: [typescript-eslint/no-unused-vars, eslint/no-unused-vars]
18
+ since: 0.1.0
19
+ ---
20
+
21
+ Every variable, function, class, type, interface, enum, import, parameter and caught error is used
22
+ somewhere. Parameters before the last used one are allowed (`args: after-used`).
23
+
24
+ **Why:** An unused declaration is dead code or a sign the code doesn't do what it was meant to.
25
+
26
+ ```codelaw
27
+ native: ts/no-unused-vars
28
+ ```
29
+
30
+ ## How to fix
31
+
32
+ 1. Check the initialiser has no side effect that matters.
33
+ 2. Remove the declaration, or use it where it was meant to be used.
34
+ 3. For a parameter that must stay for its position, prefix it with `_` and set `argsIgnorePattern: "^_"`.
35
+
36
+ ## Examples
37
+
38
+ ### TypeScript
39
+
40
+ #### Don't
41
+
42
+ ```ts
43
+ import { readFile, writeFile } from "node:fs";
44
+ export const load = (path: string) => readFile(path);
45
+ ```
46
+
47
+ #### Do
48
+
49
+ ```ts
50
+ import { readFile } from "node:fs";
51
+ export const load = (path: string) => readFile(path);
52
+ ```
53
+
54
+ ### TSX
55
+
56
+ #### Don't
57
+
58
+ ```tsx
59
+ import { readFile, writeFile } from "node:fs";
60
+ export const load = (path: string) => readFile(path);
61
+ ```
62
+
63
+ #### Do
64
+
65
+ ```tsx
66
+ import { readFile } from "node:fs";
67
+ export const load = (path: string) => readFile(path);
68
+ ```
@@ -0,0 +1,49 @@
1
+ ---
2
+ id: ts/no-wrapper-object-types
3
+ title: "Primitive types, not wrapper object types"
4
+ languages: [typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [typescript-eslint/no-wrapper-object-types]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ Types use `string`, `number`, `boolean`, `symbol`, `bigint` and `object`, not the wrapper objects
12
+ `String`, `Number`, `Boolean`, `Symbol`, `BigInt` and `Object`.
13
+
14
+ **Why:** The wrapper types describe boxed objects almost no code uses, and accept values the
15
+ primitive types reject.
16
+
17
+ ```codelaw
18
+ native: ts/no-wrapper-object-types
19
+ ```
20
+
21
+ ## Examples
22
+
23
+ ### TypeScript
24
+
25
+ #### Don't
26
+
27
+ ```ts
28
+ let label: String = "a";
29
+ ```
30
+
31
+ #### Do
32
+
33
+ ```ts
34
+ let label: string = "a";
35
+ ```
36
+
37
+ ### TSX
38
+
39
+ #### Don't
40
+
41
+ ```tsx
42
+ let label: String = "a";
43
+ ```
44
+
45
+ #### Do
46
+
47
+ ```tsx
48
+ let label: string = "a";
49
+ ```
@@ -0,0 +1,47 @@
1
+ ---
2
+ id: ts/prefer-as-const
3
+ title: "as const instead of repeating a literal as its type"
4
+ languages: [typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [typescript-eslint/prefer-as-const]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A literal cast to its own literal type (`"a" as "a"`) uses `as const` instead.
12
+
13
+ **Why:** `as const` says the same thing once, and stays right when the literal changes.
14
+
15
+ ```codelaw
16
+ native: ts/prefer-as-const
17
+ ```
18
+
19
+ ## Examples
20
+
21
+ ### TypeScript
22
+
23
+ #### Don't
24
+
25
+ ```ts
26
+ const mode = "dark" as "dark";
27
+ ```
28
+
29
+ #### Do
30
+
31
+ ```ts
32
+ const mode = "dark" as const;
33
+ ```
34
+
35
+ ### TSX
36
+
37
+ #### Don't
38
+
39
+ ```tsx
40
+ const mode = "dark" as "dark";
41
+ ```
42
+
43
+ #### Do
44
+
45
+ ```tsx
46
+ const mode = "dark" as const;
47
+ ```
@@ -0,0 +1,63 @@
1
+ ---
2
+ id: ts/prefer-namespace-keyword
3
+ title: "namespace, not module, for a TypeScript namespace"
4
+ languages: [typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [typescript-eslint/prefer-namespace-keyword]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A TypeScript namespace is declared with `namespace`, not `module`; `declare module "x"` is
12
+ unaffected.
13
+
14
+ **Why:** `module Foo {}` is the old spelling and is easy to confuse with an external module
15
+ declaration.
16
+
17
+ ```codelaw
18
+ match:
19
+ kind: module
20
+ all:
21
+ - has: { field: name, kind: identifier, pattern: $NAME }
22
+ - has: { field: body, pattern: $BODY }
23
+ message: "Write `namespace` for a TypeScript namespace; `module` is for declaring external modules"
24
+ fix: "namespace $NAME $BODY"
25
+ ```
26
+
27
+ ## Examples
28
+
29
+ ### TypeScript
30
+
31
+ #### Don't
32
+
33
+ ```ts
34
+ module Shapes {
35
+ export const sides = 4;
36
+ }
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```ts
42
+ namespace Shapes {
43
+ export const sides = 4;
44
+ }
45
+ ```
46
+
47
+ ### TSX
48
+
49
+ #### Don't
50
+
51
+ ```tsx
52
+ module Shapes {
53
+ export const sides = 4;
54
+ }
55
+ ```
56
+
57
+ #### Do
58
+
59
+ ```tsx
60
+ namespace Shapes {
61
+ export const sides = 4;
62
+ }
63
+ ```
@@ -0,0 +1,60 @@
1
+ ---
2
+ id: ts/triple-slash-reference
3
+ title: "No /// <reference path> directives"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "the matching import needs the module path and what it provides"
7
+ stability: preview
8
+ ported_from: [typescript-eslint/triple-slash-reference]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ Files are connected with `import`, not `/// <reference path="…" />`.
13
+
14
+ **Why:** Reference directives predate ES modules and hide dependencies from bundlers and other
15
+ tools.
16
+
17
+ ```codelaw
18
+ match:
19
+ kind: comment
20
+ regex: ^///\s*<reference\s+path=
21
+ message: "Use an `import` instead of a `/// <reference path>` directive"
22
+ ```
23
+
24
+ ## How to fix
25
+
26
+ 1. Replace the directive with an `import` of the module it pointed to.
27
+
28
+ ## Examples
29
+
30
+ ### TypeScript
31
+
32
+ #### Don't
33
+
34
+ ```ts
35
+ /// <reference path="./globals.d.ts" />
36
+ export const x = 1;
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```ts
42
+ import "./globals";
43
+ export const x = 1;
44
+ ```
45
+
46
+ ### TSX
47
+
48
+ #### Don't
49
+
50
+ ```tsx
51
+ /// <reference path="./globals.d.ts" />
52
+ export const x = 1;
53
+ ```
54
+
55
+ #### Do
56
+
57
+ ```tsx
58
+ import "./globals";
59
+ export const x = 1;
60
+ ```