Skip to content

Commit 606fc70

Browse files
aggmoulikbradzacher
authored andcommitted
feat(eslint-plugin): [no-explicit-any] Add an optional fixer (typescript-eslint#609)
1 parent 76b89a5 commit 606fc70

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

packages/eslint-plugin/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
145145
| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :heavy_check_mark: | :wrench: | |
146146
| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | | | |
147147
| [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | | |
148-
| [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | | |
148+
| [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | :wrench: | |
149149
| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
150150
| [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | |
151151
| [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately. | | | :thought_balloon: |

packages/eslint-plugin/docs/rules/no-explicit-any.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,24 @@ function greet(param: Array<string>): string {}
8787
function greet(param: Array<string>): Array<string> {}
8888
```
8989

90+
## Options
91+
92+
The rule accepts an options object with the following properties:
93+
94+
```ts
95+
type Options = {
96+
// if true, auto-fixing will be made available in which the "any" type is converted to an "unknown" type
97+
fixToUnknown: boolean;
98+
// specify if arrays from the rest operator are considered okay
99+
ignoreRestArgs: boolean;
100+
};
101+
102+
const defaults = {
103+
fixToUnknown: false,
104+
ignoreRestArgs: false,
105+
};
106+
```
107+
90108
### ignoreRestArgs
91109

92110
A boolean to specify if arrays from the rest operator are considered okay. `false` by default.

packages/eslint-plugin/src/rules/no-explicit-any.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,17 @@ import {
33
AST_NODE_TYPES,
44
} from '@typescript-eslint/experimental-utils';
55
import * as util from '../util';
6+
import { TSESLint } from '@typescript-eslint/experimental-utils';
67

7-
export default util.createRule({
8+
export type Options = [
9+
{
10+
fixToUnknown?: boolean;
11+
ignoreRestArgs?: boolean;
12+
}
13+
];
14+
export type MessageIds = 'unexpectedAny';
15+
16+
export default util.createRule<Options, MessageIds>({
817
name: 'no-explicit-any',
918
meta: {
1019
type: 'suggestion',
@@ -13,6 +22,7 @@ export default util.createRule({
1322
category: 'Best Practices',
1423
recommended: 'warn',
1524
},
25+
fixable: 'code',
1626
messages: {
1727
unexpectedAny: 'Unexpected any. Specify a different type.',
1828
},
@@ -21,6 +31,9 @@ export default util.createRule({
2131
type: 'object',
2232
additionalProperties: false,
2333
properties: {
34+
fixToUnknown: {
35+
type: 'boolean',
36+
},
2437
ignoreRestArgs: {
2538
type: 'boolean',
2639
},
@@ -30,10 +43,11 @@ export default util.createRule({
3043
},
3144
defaultOptions: [
3245
{
46+
fixToUnknown: false,
3347
ignoreRestArgs: false,
3448
},
3549
],
36-
create(context, [{ ignoreRestArgs }]) {
50+
create(context, [{ ignoreRestArgs, fixToUnknown }]) {
3751
/**
3852
* Checks if the node is an arrow function, function declaration or function expression
3953
* @param node the node to be validated.
@@ -155,9 +169,17 @@ export default util.createRule({
155169
if (ignoreRestArgs && isNodeDescendantOfRestElementInFunction(node)) {
156170
return;
157171
}
172+
173+
let fix: TSESLint.ReportFixFunction | null = null;
174+
175+
if (fixToUnknown) {
176+
fix = fixer => fixer.replaceText(node, 'unknown');
177+
}
178+
158179
context.report({
159180
node,
160181
messageId: 'unexpectedAny',
182+
fix,
161183
});
162184
},
163185
};

packages/eslint-plugin/tests/rules/no-explicit-any.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import rule from '../../src/rules/no-explicit-any';
1+
import rule, { MessageIds, Options } from '../../src/rules/no-explicit-any';
22
import { RuleTester } from '../RuleTester';
3+
import { TSESLint } from '@typescript-eslint/experimental-utils';
4+
5+
type InvalidTestCase = TSESLint.InvalidTestCase<MessageIds, Options>;
36

47
const ruleTester = new RuleTester({
58
parser: '@typescript-eslint/parser',
@@ -187,7 +190,7 @@ type obj = {
187190
options: [{ ignoreRestArgs: true }],
188191
},
189192
],
190-
invalid: [
193+
invalid: ([
191194
{
192195
code: 'const number: any = 1',
193196
errors: [
@@ -784,5 +787,23 @@ type obj = {
784787
},
785788
],
786789
},
787-
],
790+
] as InvalidTestCase[]).reduce<InvalidTestCase[]>((acc, testCase) => {
791+
acc.push(testCase);
792+
const options = testCase.options || [];
793+
const code = `// fixToUnknown: true\n${testCase.code}`;
794+
acc.push({
795+
code,
796+
output: code.replace(/any/g, 'unknown'),
797+
options: [{ ...options[0], fixToUnknown: true }],
798+
errors: testCase.errors.map(err => {
799+
if (err.line === undefined) {
800+
return err;
801+
}
802+
803+
return { ...err, line: err.line + 1 };
804+
}),
805+
});
806+
807+
return acc;
808+
}, []),
788809
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy