@codelaw/rules-ts 0.0.0-stage → 0.2.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/LICENSE +23 -0
- package/NOTICE +6 -0
- package/README.md +38 -2
- package/codelaw-pack.toml +6 -0
- package/corpus.toml +25 -0
- package/package.json +14 -4
- package/presets/ts/conventions.toml +4 -0
- package/presets/ts/recommended.toml +23 -0
- package/rules/ts/ban-ts-comment.md +64 -0
- package/rules/ts/no-array-constructor.md +58 -0
- package/rules/ts/no-duplicate-enum-values.md +65 -0
- package/rules/ts/no-empty-object-type.md +65 -0
- package/rules/ts/no-explicit-any.md +61 -0
- package/rules/ts/no-extra-non-null-assertion.md +50 -0
- package/rules/ts/no-misused-new.md +70 -0
- package/rules/ts/no-namespace.md +65 -0
- package/rules/ts/no-non-null-asserted-optional-chain.md +55 -0
- package/rules/ts/no-require-imports.md +54 -0
- package/rules/ts/no-this-alias.md +68 -0
- package/rules/ts/no-unnecessary-type-constraint.md +64 -0
- package/rules/ts/no-unsafe-declaration-merging.md +73 -0
- package/rules/ts/no-unsafe-function-type.md +57 -0
- package/rules/ts/no-unused-expressions.md +61 -0
- package/rules/ts/no-unused-vars.md +68 -0
- package/rules/ts/no-wrapper-object-types.md +49 -0
- package/rules/ts/prefer-as-const.md +47 -0
- package/rules/ts/prefer-namespace-keyword.md +63 -0
- package/rules/ts/triple-slash-reference.md +60 -0
- package/rules/ts/type-only-imports.md +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arpit Arya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
SPDX-License-Identifier: MIT
|
package/NOTICE
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
@codelaw/rules-ts
|
|
2
|
+
|
|
3
|
+
The rules are reimplementations written for codelaw. Their `ported_from:`
|
|
4
|
+
fields name the typescript-eslint rules (https://typescript-eslint.io, MIT
|
|
5
|
+
License) whose documented behaviour they reproduce; no typescript-eslint code
|
|
6
|
+
or documentation text is included.
|
package/README.md
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @codelaw/rules-ts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
codelaw's TypeScript rules — one of codelaw's first-party rule packs
|
|
4
|
+
([SR-RULE-PACKS](../../records/0101_rule-packs.md)). It ships on
|
|
5
|
+
npm only, as `@codelaw/rules-ts`; PyPI has no copy (L6 decision 11).
|
|
6
|
+
|
|
7
|
+
```toml
|
|
8
|
+
# codelaw.toml
|
|
9
|
+
extends = ["codelaw:js/recommended", "codelaw:js/typescript", "codelaw:ts/recommended"]
|
|
10
|
+
preview = true # every rule is `preview` until a corpus run promotes it
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Presets
|
|
14
|
+
|
|
15
|
+
<!-- docs-sync:presets -->
|
|
16
|
+
|
|
17
|
+
| preset | rules | ported from |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `ts/recommended` | 20 | typescript-eslint `recommended` 8.71.2 (not type-checked) — all 20 rules; the four core rules its `eslint-recommended` switches on are `codelaw:js/typescript` in `@codelaw/rules-js` |
|
|
20
|
+
| `ts/conventions` | 1 | codelaw's starter catalogue: `ts/type-only-imports` — opt in |
|
|
21
|
+
|
|
22
|
+
<!-- /docs-sync:presets -->
|
|
23
|
+
|
|
24
|
+
Every rule is **reimplemented**, not vendored: the matchers, messages and docs
|
|
25
|
+
are written fresh, and each rule's `ported_from:` names the source rule.
|
|
26
|
+
|
|
27
|
+
## How the ports differ
|
|
28
|
+
|
|
29
|
+
Every rule matches its source's documented behaviour on the source's own
|
|
30
|
+
examples. Where codelaw differs, the rule's `## Differences from the source`
|
|
31
|
+
section says so. The larger ones:
|
|
32
|
+
|
|
33
|
+
| rule | difference |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `ts/no-unused-expressions` | `x satisfies T;` is a compile-time type test and is allowed |
|
|
36
|
+
|
|
37
|
+
Nothing from typescript-eslint's non-type-checked `recommended` is left out.
|
|
38
|
+
Every `*-type-checked` typescript-eslint config is out of scope: those rules
|
|
39
|
+
need type information (L3).
|
package/corpus.toml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `codelaw test --corpus` finding counts (SR-RULE-AUTHORING decision 4).
|
|
2
|
+
# Rewrite with --update-snapshot, and review the change.
|
|
3
|
+
|
|
4
|
+
[findings]
|
|
5
|
+
"ts/ban-ts-comment" = 96
|
|
6
|
+
"ts/no-array-constructor" = 0
|
|
7
|
+
"ts/no-duplicate-enum-values" = 0
|
|
8
|
+
"ts/no-empty-object-type" = 276
|
|
9
|
+
"ts/no-explicit-any" = 1653
|
|
10
|
+
"ts/no-extra-non-null-assertion" = 0
|
|
11
|
+
"ts/no-misused-new" = 0
|
|
12
|
+
"ts/no-namespace" = 1
|
|
13
|
+
"ts/no-non-null-asserted-optional-chain" = 0
|
|
14
|
+
"ts/no-require-imports" = 3
|
|
15
|
+
"ts/no-this-alias" = 1
|
|
16
|
+
"ts/no-unnecessary-type-constraint" = 0
|
|
17
|
+
"ts/no-unsafe-declaration-merging" = 173
|
|
18
|
+
"ts/no-unsafe-function-type" = 8
|
|
19
|
+
"ts/no-unused-expressions" = 39
|
|
20
|
+
"ts/no-unused-vars" = 318
|
|
21
|
+
"ts/no-wrapper-object-types" = 0
|
|
22
|
+
"ts/prefer-as-const" = 0
|
|
23
|
+
"ts/prefer-namespace-keyword" = 0
|
|
24
|
+
"ts/triple-slash-reference" = 0
|
|
25
|
+
"ts/type-only-imports" = 797
|
package/package.json
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codelaw/rules-ts",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "codelaw's TypeScript rules, from typescript-eslint; npm only (SR-RULE-PACKS)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/arpitarya/codelaw.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/arpitarya/codelaw",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"codelaw",
|
|
13
|
+
"codelaw-pack",
|
|
14
|
+
"lint-rules"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
description = "typescript-eslint's recommended preset (8.71.2, not type-checked), reimplemented; the core rules it switches on for TypeScript are codelaw:js/typescript"
|
|
2
|
+
|
|
3
|
+
[rules]
|
|
4
|
+
"ts/ban-ts-comment" = "error"
|
|
5
|
+
"ts/no-array-constructor" = "error"
|
|
6
|
+
"ts/no-duplicate-enum-values" = "error"
|
|
7
|
+
"ts/no-empty-object-type" = "error"
|
|
8
|
+
"ts/no-explicit-any" = "error"
|
|
9
|
+
"ts/no-extra-non-null-assertion" = "error"
|
|
10
|
+
"ts/no-misused-new" = "error"
|
|
11
|
+
"ts/no-namespace" = "error"
|
|
12
|
+
"ts/no-non-null-asserted-optional-chain" = "error"
|
|
13
|
+
"ts/no-require-imports" = "error"
|
|
14
|
+
"ts/no-this-alias" = "error"
|
|
15
|
+
"ts/no-unnecessary-type-constraint" = "error"
|
|
16
|
+
"ts/no-unsafe-declaration-merging" = "error"
|
|
17
|
+
"ts/no-unsafe-function-type" = "error"
|
|
18
|
+
"ts/no-unused-expressions" = "error"
|
|
19
|
+
"ts/no-unused-vars" = "error"
|
|
20
|
+
"ts/no-wrapper-object-types" = "error"
|
|
21
|
+
"ts/prefer-as-const" = "error"
|
|
22
|
+
"ts/prefer-namespace-keyword" = "error"
|
|
23
|
+
"ts/triple-slash-reference" = "error"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/ban-ts-comment
|
|
3
|
+
title: "No @ts-ignore or @ts-nocheck; @ts-expect-error says why"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the reason the error is expected has to come from the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [typescript-eslint/ban-ts-comment]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Type-checking is never switched off with `@ts-ignore` or `@ts-nocheck`, and a `@ts-expect-error`
|
|
13
|
+
says why the error is expected.
|
|
14
|
+
|
|
15
|
+
**Why:** `@ts-ignore` hides an error for good, even after the code it excused changes; `@ts-expect-
|
|
16
|
+
error` fails as soon as the error is gone.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
match:
|
|
20
|
+
kind: comment
|
|
21
|
+
any:
|
|
22
|
+
- regex: ^(//|/\*)\s*@ts-(ignore|nocheck)\b
|
|
23
|
+
- regex: ^(//|/\*)\s*@ts-expect-error\s*(\*/)?$
|
|
24
|
+
message: "Don't silence the compiler with `@ts-ignore` or `@ts-nocheck`; use `@ts-expect-error: <why>`"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How to fix
|
|
28
|
+
|
|
29
|
+
1. Fix the type error if you can.
|
|
30
|
+
2. Otherwise replace the comment with `// @ts-expect-error: <why>`.
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
### TypeScript
|
|
35
|
+
|
|
36
|
+
#### Don't
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
const n: number = "1";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### Do
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// @ts-expect-error: the fixture checks the compiler's message
|
|
47
|
+
const n: number = "1";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### TSX
|
|
51
|
+
|
|
52
|
+
#### Don't
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
const n: number = "1";
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Do
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// @ts-expect-error: the fixture checks the compiler's message
|
|
63
|
+
const n: number = "1";
|
|
64
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-array-constructor
|
|
3
|
+
title: "No Array constructor with several arguments"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: auto
|
|
6
|
+
stability: preview
|
|
7
|
+
ported_from: [typescript-eslint/no-array-constructor, eslint/no-array-constructor]
|
|
8
|
+
since: 0.1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Arrays are built with literals; `new Array(n)` with one argument (a length) is allowed.
|
|
12
|
+
|
|
13
|
+
**Why:** `new Array(a, b)` and `new Array(n)` mean different things, and the literal says what it
|
|
14
|
+
means.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
match:
|
|
18
|
+
any:
|
|
19
|
+
- pattern: new Array($$$ARGS)
|
|
20
|
+
- pattern: Array($$$ARGS)
|
|
21
|
+
not:
|
|
22
|
+
any:
|
|
23
|
+
- pattern: new Array($ONE)
|
|
24
|
+
- pattern: Array($ONE)
|
|
25
|
+
- has: { field: type_arguments, pattern: $T }
|
|
26
|
+
message: "Use an array literal instead of the Array constructor"
|
|
27
|
+
fix: "[$$$ARGS]"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### TypeScript
|
|
33
|
+
|
|
34
|
+
#### Don't
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const xs = new Array(1, 2, 3);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Do
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const xs = [1, 2, 3];
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### TSX
|
|
47
|
+
|
|
48
|
+
#### Don't
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
const xs = new Array(1, 2, 3);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Do
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
const xs = [1, 2, 3];
|
|
58
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-duplicate-enum-values
|
|
3
|
+
title: "No two enum members share a value"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "which value is right needs the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [typescript-eslint/no-duplicate-enum-values]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Each member of an enum given a literal value has a different value.
|
|
13
|
+
|
|
14
|
+
**Why:** Two members with one value are indistinguishable at run time, which is usually a copy-paste
|
|
15
|
+
slip.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
native: ts/no-duplicate-enum-values
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How to fix
|
|
22
|
+
|
|
23
|
+
1. Give each member its own value.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### TypeScript
|
|
28
|
+
|
|
29
|
+
#### Don't
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
enum Color {
|
|
33
|
+
Red = 1,
|
|
34
|
+
Green = 1,
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### Do
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
enum Color {
|
|
42
|
+
Red = 1,
|
|
43
|
+
Green = 2,
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### TSX
|
|
48
|
+
|
|
49
|
+
#### Don't
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
enum Color {
|
|
53
|
+
Red = 1,
|
|
54
|
+
Green = 1,
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Do
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
enum Color {
|
|
62
|
+
Red = 1,
|
|
63
|
+
Green = 2,
|
|
64
|
+
}
|
|
65
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-empty-object-type
|
|
3
|
+
title: "No empty interfaces or {} types"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the right replacement — `object`, `unknown` or `Record<string, never>` — depends on intent"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [typescript-eslint/no-empty-object-type]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Code doesn't declare an empty interface or use the type `{}`.
|
|
13
|
+
|
|
14
|
+
**Why:** `{}` accepts every value except `null` and `undefined`, which is almost never what an
|
|
15
|
+
empty-looking type was meant to say.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
match:
|
|
19
|
+
any:
|
|
20
|
+
- kind: interface_declaration
|
|
21
|
+
has: { field: body, regex: '^\{\s*\}$' }
|
|
22
|
+
- kind: object_type
|
|
23
|
+
regex: '^\{\s*\}$'
|
|
24
|
+
message: "`{}` means any non-null value, not an empty object; say what you mean"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How to fix
|
|
28
|
+
|
|
29
|
+
1. For any object, use `object`.
|
|
30
|
+
2. For any value, use `unknown`.
|
|
31
|
+
3. For an object with no keys, use `Record<string, never>`.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
### TypeScript
|
|
36
|
+
|
|
37
|
+
#### Don't
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
interface Options {}
|
|
41
|
+
type Empty = {};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
#### Do
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
type Options = Record<string, never>;
|
|
48
|
+
type Anything = unknown;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### TSX
|
|
52
|
+
|
|
53
|
+
#### Don't
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
interface Options {}
|
|
57
|
+
type Empty = {};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Do
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
type Options = Record<string, never>;
|
|
64
|
+
type Anything = unknown;
|
|
65
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-explicit-any
|
|
3
|
+
title: "No explicit any"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: suggest
|
|
6
|
+
fix_reason: "`unknown` may need narrowing code where the value is used"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [typescript-eslint/no-explicit-any]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Types are not written as `any`.
|
|
13
|
+
|
|
14
|
+
**Why:** `any` silently disables checking for everything it touches; `unknown` keeps the checks and
|
|
15
|
+
forces a narrowing.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
match:
|
|
19
|
+
kind: predefined_type
|
|
20
|
+
regex: ^any$
|
|
21
|
+
message: "`any` turns off type-checking here; use `unknown` and narrow it"
|
|
22
|
+
fix: "unknown"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### TypeScript
|
|
28
|
+
|
|
29
|
+
#### Don't
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
function parse(input: any) {
|
|
33
|
+
return input;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### Do
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
function parse(input: unknown) {
|
|
41
|
+
return input;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### TSX
|
|
46
|
+
|
|
47
|
+
#### Don't
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function parse(input: any) {
|
|
51
|
+
return input;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
#### Do
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
function parse(input: unknown) {
|
|
59
|
+
return input;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-extra-non-null-assertion
|
|
3
|
+
title: "No repeated non-null assertions"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: auto
|
|
6
|
+
stability: preview
|
|
7
|
+
ported_from: [typescript-eslint/no-extra-non-null-assertion]
|
|
8
|
+
since: 0.1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
A non-null assertion `!` is not repeated.
|
|
12
|
+
|
|
13
|
+
**Why:** `x!!` means the same as `x!`; the second `!` is a typo.
|
|
14
|
+
|
|
15
|
+
```codelaw
|
|
16
|
+
match:
|
|
17
|
+
pattern: $X!!
|
|
18
|
+
message: "One `!` is enough"
|
|
19
|
+
fix: "$X!"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
### TypeScript
|
|
25
|
+
|
|
26
|
+
#### Don't
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
const n = value!!;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### Do
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
const n = value!;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### TSX
|
|
39
|
+
|
|
40
|
+
#### Don't
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
const n = value!!;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Do
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
const n = value!;
|
|
50
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-misused-new
|
|
3
|
+
title: "No constructors declared in interfaces, and no `new` methods in classes"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the intended constructor signature needs the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [typescript-eslint/no-misused-new]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
An interface doesn't declare a method named `constructor`, and a class doesn't declare a method
|
|
13
|
+
named `new`.
|
|
14
|
+
|
|
15
|
+
**Why:** Both look like constructors but are ordinary methods; constructors in types are written
|
|
16
|
+
`new (): T`.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
match:
|
|
20
|
+
any:
|
|
21
|
+
- kind: method_signature
|
|
22
|
+
has: { field: name, regex: ^constructor$ }
|
|
23
|
+
inside: { kind: interface_body, stopBy: neighbor }
|
|
24
|
+
- kind: method_definition
|
|
25
|
+
has: { field: name, regex: ^new$ }
|
|
26
|
+
message: "This declares a constructor where TypeScript reads a plain method"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## How to fix
|
|
30
|
+
|
|
31
|
+
1. In an interface, describe a constructor with `new (…): T`.
|
|
32
|
+
2. In a class, use `constructor(…)`.
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
### TypeScript
|
|
37
|
+
|
|
38
|
+
#### Don't
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
interface Point {
|
|
42
|
+
constructor(): void;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Do
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
interface PointConstructor {
|
|
50
|
+
new (): object;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### TSX
|
|
55
|
+
|
|
56
|
+
#### Don't
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
interface Point {
|
|
60
|
+
constructor(): void;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Do
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
interface PointConstructor {
|
|
68
|
+
new (): object;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ts/no-namespace
|
|
3
|
+
title: "No TypeScript namespaces"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "moving a namespace's members into a module changes every import"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [typescript-eslint/no-namespace]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Code is organised with ES modules, not `namespace` or `module` blocks; `declare module "x"` and
|
|
13
|
+
`declare global` are allowed.
|
|
14
|
+
|
|
15
|
+
**Why:** Namespaces predate ES modules and don't work with modern bundlers and tooling as well.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
match:
|
|
19
|
+
any:
|
|
20
|
+
- kind: internal_module
|
|
21
|
+
- kind: module
|
|
22
|
+
has: { field: name, kind: identifier }
|
|
23
|
+
not:
|
|
24
|
+
inside: { kind: ambient_declaration, stopBy: end }
|
|
25
|
+
message: "Use ES modules instead of a namespace"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## How to fix
|
|
29
|
+
|
|
30
|
+
1. Move the namespace's members to a module of their own.
|
|
31
|
+
2. Export them, and import them where the namespace was used.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
### TypeScript
|
|
36
|
+
|
|
37
|
+
#### Don't
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
namespace Geometry {
|
|
41
|
+
export const pi = 3.14;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### Do
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
export const pi = 3.14;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### TSX
|
|
52
|
+
|
|
53
|
+
#### Don't
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
namespace Geometry {
|
|
57
|
+
export const pi = 3.14;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Do
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
export const pi = 3.14;
|
|
65
|
+
```
|