Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7021f21

Browse files
authored
feat(eslint-plugin): add rule prefer-ts-expect-error (typescript-eslint#1705)
1 parent 469cff3 commit 7021f21

File tree

7 files changed

+192
-0
lines changed

7 files changed

+192
-0
lines changed

packages/eslint-plugin/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int
152152
| [`@typescript-eslint/prefer-reduce-type-parameter`](./docs/rules/prefer-reduce-type-parameter.md) | Prefer using type parameter when calling `Array#reduce` instead of casting | | :wrench: | :thought_balloon: |
153153
| [`@typescript-eslint/prefer-regexp-exec`](./docs/rules/prefer-regexp-exec.md) | Enforce that `RegExp#exec` is used instead of `String#match` if no global flag is provided | :heavy_check_mark: | | :thought_balloon: |
154154
| [`@typescript-eslint/prefer-string-starts-ends-with`](./docs/rules/prefer-string-starts-ends-with.md) | Enforce the use of `String#startsWith` and `String#endsWith` instead of other equivalent methods of checking substrings | :heavy_check_mark: | :wrench: | :thought_balloon: |
155+
| [`@typescript-eslint/prefer-ts-expect-error`](./docs/rules/prefer-ts-expect-error.md) | Recommends using `// @ts-expect-error` over `// @ts-ignore` | | :wrench: | |
155156
| [`@typescript-eslint/promise-function-async`](./docs/rules/promise-function-async.md) | Requires any function or method that returns a Promise to be marked async | | | :thought_balloon: |
156157
| [`@typescript-eslint/require-array-sort-compare`](./docs/rules/require-array-sort-compare.md) | Requires `Array#sort` calls to always provide a `compareFunction` | | | :thought_balloon: |
157158
| [`@typescript-eslint/restrict-plus-operands`](./docs/rules/restrict-plus-operands.md) | When adding two variables, operands must both be of type number or of type string | | | :thought_balloon: |
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Recommends using `// @ts-expect-error` over `// @ts-ignore` (`prefer-ts-expect-error`)
2+
3+
TypeScript allows you to suppress all errors on a line by placing a single-line comment starting with `@ts-ignore` immediately before the erroring line.
4+
While powerful, there is no way to know if a `@ts-ignore` is actually suppressing an error without manually investigating what happens when the `@ts-ignore` is removed.
5+
6+
This means its easy for `@ts-ignore`s to be forgotten about, and remain in code even after the error they were suppressing is fixed.
7+
This is dangerous, as if a new error arises on that line it'll be suppressed by the forgotten about `@ts-ignore`, and so be missed.
8+
9+
To address this, TS3.9 ships with a new single-line comment directive: `// @ts-expect-error`.
10+
11+
This directive operates in the same manner as `@ts-ignore`, but will error if the line it's meant to be suppressing doesn't actually contain an error, making it a lot safer.
12+
13+
## Rule Details
14+
15+
This rule looks for usages of `@ts-ignore`, and flags them to be replaced with `@ts-expect-error`.
16+
17+
Examples of **incorrect** code for this rule:
18+
19+
```ts
20+
// @ts-ignore
21+
const str: string = 1;
22+
23+
const isOptionEnabled = (key: string): boolean => {
24+
// @ts-ignore: if key isn't in globalOptions it'll be undefined which is false
25+
return !!globalOptions[key];
26+
};
27+
```
28+
29+
Examples of **correct** code for this rule:
30+
31+
```ts
32+
// @ts-expect-error
33+
const str: string = 1;
34+
35+
const isOptionEnabled = (key: string): boolean => {
36+
// @ts-expect-error: if key isn't in globalOptions it'll be undefined which is false
37+
return !!globalOptions[key];
38+
};
39+
```
40+
41+
## When Not To Use It
42+
43+
If you are not using TypeScript 3.9 (or greater), then you will not be able to use this rule, as the directive is not supported
44+
45+
## Further Reading
46+
47+
- [Original Implementing PR](https://github.com/microsoft/TypeScript/pull/36014)

packages/eslint-plugin/src/configs/all.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"@typescript-eslint/prefer-reduce-type-parameter": "error",
9090
"@typescript-eslint/prefer-regexp-exec": "error",
9191
"@typescript-eslint/prefer-string-starts-ends-with": "error",
92+
"@typescript-eslint/prefer-ts-expect-error": "error",
9293
"@typescript-eslint/promise-function-async": "error",
9394
"quotes": "off",
9495
"@typescript-eslint/quotes": "error",

packages/eslint-plugin/src/rules/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import preferReadonlyParameterTypes from './prefer-readonly-parameter-types';
7878
import preferReduceTypeParameter from './prefer-reduce-type-parameter';
7979
import preferRegexpExec from './prefer-regexp-exec';
8080
import preferStringStartsEndsWith from './prefer-string-starts-ends-with';
81+
import preferTsExpectError from './prefer-ts-expect-error';
8182
import promiseFunctionAsync from './promise-function-async';
8283
import quotes from './quotes';
8384
import requireArraySortCompare from './require-array-sort-compare';
@@ -176,6 +177,7 @@ export default {
176177
'prefer-reduce-type-parameter': preferReduceTypeParameter,
177178
'prefer-regexp-exec': preferRegexpExec,
178179
'prefer-string-starts-ends-with': preferStringStartsEndsWith,
180+
'prefer-ts-expect-error': preferTsExpectError,
179181
'promise-function-async': promiseFunctionAsync,
180182
quotes: quotes,
181183
'require-array-sort-compare': requireArraySortCompare,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { AST_TOKEN_TYPES } from '@typescript-eslint/experimental-utils';
2+
import * as util from '../util';
3+
4+
type MessageIds = 'preferExpectErrorComment';
5+
6+
export default util.createRule<[], MessageIds>({
7+
name: 'prefer-ts-expect-error',
8+
meta: {
9+
type: 'problem',
10+
docs: {
11+
description:
12+
'Recommends using `// @ts-expect-error` over `// @ts-ignore`',
13+
category: 'Best Practices',
14+
recommended: false,
15+
},
16+
fixable: 'code',
17+
messages: {
18+
preferExpectErrorComment:
19+
'Use "// @ts-expect-error" to ensure an error is actually being suppressed.',
20+
},
21+
schema: [],
22+
},
23+
defaultOptions: [],
24+
create(context) {
25+
const tsIgnoreRegExp = /^\/*\s*@ts-ignore/;
26+
const sourceCode = context.getSourceCode();
27+
28+
return {
29+
Program(): void {
30+
const comments = sourceCode.getAllComments();
31+
32+
comments.forEach(comment => {
33+
if (comment.type !== AST_TOKEN_TYPES.Line) {
34+
return;
35+
}
36+
37+
if (tsIgnoreRegExp.test(comment.value)) {
38+
context.report({
39+
node: comment,
40+
messageId: 'preferExpectErrorComment',
41+
fix: fixer =>
42+
fixer.replaceText(
43+
comment,
44+
`//${comment.value.replace(
45+
'@ts-ignore',
46+
'@ts-expect-error',
47+
)}`,
48+
),
49+
});
50+
}
51+
});
52+
},
53+
};
54+
},
55+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import rule from '../../src/rules/prefer-ts-expect-error';
2+
import { RuleTester } from '../RuleTester';
3+
4+
const ruleTester = new RuleTester({
5+
parser: '@typescript-eslint/parser',
6+
});
7+
8+
ruleTester.run('prefer-ts-expect-error', rule, {
9+
valid: [
10+
'// @ts-nocheck',
11+
'// @ts-check',
12+
'// just a comment containing @ts-ignore somewhere',
13+
'/* @ts-ignore */',
14+
'/** @ts-ignore */',
15+
`
16+
/*
17+
// @ts-ignore in a block
18+
*/
19+
`,
20+
'// @ts-expect-error',
21+
`
22+
if (false) {
23+
// @ts-expect-error: Unreachable code error
24+
console.log('hello');
25+
}
26+
`,
27+
],
28+
invalid: [
29+
{
30+
code: '// @ts-ignore',
31+
output: '// @ts-expect-error',
32+
errors: [
33+
{
34+
messageId: 'preferExpectErrorComment',
35+
line: 1,
36+
column: 1,
37+
},
38+
],
39+
},
40+
{
41+
code: '// @ts-ignore: Suppress next line',
42+
output: '// @ts-expect-error: Suppress next line',
43+
44+
errors: [
45+
{
46+
messageId: 'preferExpectErrorComment',
47+
line: 1,
48+
column: 1,
49+
},
50+
],
51+
},
52+
{
53+
code: '/////@ts-ignore: Suppress next line',
54+
output: '/////@ts-expect-error: Suppress next line',
55+
errors: [
56+
{
57+
messageId: 'preferExpectErrorComment',
58+
line: 1,
59+
column: 1,
60+
},
61+
],
62+
},
63+
{
64+
code: `
65+
if (false) {
66+
// @ts-ignore: Unreachable code error
67+
console.log('hello');
68+
}
69+
`,
70+
output: `
71+
if (false) {
72+
// @ts-expect-error: Unreachable code error
73+
console.log('hello');
74+
}
75+
`,
76+
errors: [
77+
{
78+
messageId: 'preferExpectErrorComment',
79+
line: 3,
80+
column: 3,
81+
},
82+
],
83+
},
84+
],
85+
});

packages/typescript-estree/src/ts-estree/ts-estree.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export interface LineComment extends BaseToken {
115115
export type Comment = BlockComment | LineComment;
116116
export type Token =
117117
| BooleanToken
118+
| Comment
118119
| IdentifierToken
119120
| JSXIdentifierToken
120121
| JSXTextToken

0 commit comments

Comments
 (0)