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

Skip to content

Commit 2788545

Browse files
authored
feat(eslint-plugin): [restrict-plus-operand] add allowAny option (typescript-eslint#4260)
1 parent ff0adf9 commit 2788545

File tree

3 files changed

+243
-18
lines changed

3 files changed

+243
-18
lines changed

packages/eslint-plugin/docs/rules/restrict-plus-operands.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,25 @@ var foo = 1n + 1n;
2222

2323
## Options
2424

25-
This rule has an object option:
25+
The rule accepts an options object with the following properties:
2626

27-
- `"checkCompoundAssignments": false`: (default) does not check compound assignments (`+=`)
28-
- `"checkCompoundAssignments": true`
27+
```ts
28+
type Options = {
29+
// if true, check compound assignments (`+=`)
30+
checkCompoundAssignments?: boolean;
31+
// if true, 'any' itself and `string`,`bigint`, `number` is allowed.
32+
allowAny?: boolean;
33+
};
34+
35+
const defaults = {
36+
checkCompoundAssignments: false,
37+
allowAny: false,
38+
};
39+
```
2940

3041
### `checkCompoundAssignments`
3142

32-
Examples of code for the `{ "checkCompoundAssignments": true }` option:
43+
Examples of code for this rule with `{ checkCompoundAssignments: true }`:
3344

3445
<!--tabs-->
3546

@@ -57,6 +68,29 @@ let bar = '';
5768
bar += 'test';
5869
```
5970

71+
### `allowAny`
72+
73+
Examples of code for this rule with `{ allowAny: true }`:
74+
75+
<!--tabs-->
76+
77+
#### ❌ Incorrect
78+
79+
```ts
80+
var fn = (a: any, b: boolean) => a + b;
81+
var fn = (a: any, b: []) => a + b;
82+
var fn = (a: any, b: {}) => a + b;
83+
```
84+
85+
#### ✅ Correct
86+
87+
```ts
88+
var fn = (a: any, b: any) => a + b;
89+
var fn = (a: any, b: string) => a + b;
90+
var fn = (a: any, b: bigint) => a + b;
91+
var fn = (a: any, b: number) => a + b;
92+
```
93+
6094
## How to Use
6195

6296
```json

packages/eslint-plugin/src/rules/restrict-plus-operands.ts

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as util from '../util';
55
type Options = [
66
{
77
checkCompoundAssignments?: boolean;
8+
allowAny?: boolean;
89
},
910
];
1011
type MessageIds = 'notNumbers' | 'notStrings' | 'notBigInts';
@@ -34,20 +35,24 @@ export default util.createRule<Options, MessageIds>({
3435
checkCompoundAssignments: {
3536
type: 'boolean',
3637
},
38+
allowAny: {
39+
type: 'boolean',
40+
},
3741
},
3842
},
3943
],
4044
},
4145
defaultOptions: [
4246
{
4347
checkCompoundAssignments: false,
48+
allowAny: false,
4449
},
4550
],
46-
create(context, [{ checkCompoundAssignments }]) {
51+
create(context, [{ checkCompoundAssignments, allowAny }]) {
4752
const service = util.getParserServices(context);
4853
const typeChecker = service.program.getTypeChecker();
4954

50-
type BaseLiteral = 'string' | 'number' | 'bigint' | 'invalid';
55+
type BaseLiteral = 'string' | 'number' | 'bigint' | 'invalid' | 'any';
5156

5257
/**
5358
* Helper function to get base type of node
@@ -82,7 +87,8 @@ export default util.createRule<Options, MessageIds>({
8287
if (
8388
stringType === 'number' ||
8489
stringType === 'string' ||
85-
stringType === 'bigint'
90+
stringType === 'bigint' ||
91+
stringType === 'any'
8692
) {
8793
return stringType;
8894
}
@@ -108,28 +114,53 @@ export default util.createRule<Options, MessageIds>({
108114
const leftType = getNodeType(node.left);
109115
const rightType = getNodeType(node.right);
110116

111-
if (
112-
leftType === 'invalid' ||
113-
rightType === 'invalid' ||
114-
leftType !== rightType
115-
) {
116-
if (leftType === 'string' || rightType === 'string') {
117+
if (leftType === rightType) {
118+
if (leftType === 'invalid') {
117119
context.report({
118120
node,
119-
messageId: 'notStrings',
121+
messageId: 'notNumbers',
120122
});
121-
} else if (leftType === 'bigint' || rightType === 'bigint') {
123+
}
124+
125+
if (!allowAny && leftType === 'any') {
122126
context.report({
123127
node,
124-
messageId: 'notBigInts',
128+
messageId: 'notNumbers',
125129
});
126-
} else {
130+
}
131+
132+
return;
133+
}
134+
135+
if (leftType === 'any' || rightType === 'any') {
136+
if (!allowAny || leftType === 'invalid' || rightType === 'invalid') {
127137
context.report({
128138
node,
129139
messageId: 'notNumbers',
130140
});
131141
}
142+
143+
return;
132144
}
145+
146+
if (leftType === 'string' || rightType === 'string') {
147+
return context.report({
148+
node,
149+
messageId: 'notStrings',
150+
});
151+
}
152+
153+
if (leftType === 'bigint' || rightType === 'bigint') {
154+
return context.report({
155+
node,
156+
messageId: 'notBigInts',
157+
});
158+
}
159+
160+
context.report({
161+
node,
162+
messageId: 'notNumbers',
163+
});
133164
}
134165

135166
return {

packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,46 @@ foo += 'string';
139139
},
140140
],
141141
},
142+
{
143+
code: `
144+
export const f = (a: any, b: any) => a + b;
145+
`,
146+
options: [
147+
{
148+
allowAny: true,
149+
},
150+
],
151+
},
152+
{
153+
code: `
154+
export const f = (a: any, b: string) => a + b;
155+
`,
156+
options: [
157+
{
158+
allowAny: true,
159+
},
160+
],
161+
},
162+
{
163+
code: `
164+
export const f = (a: any, b: bigint) => a + b;
165+
`,
166+
options: [
167+
{
168+
allowAny: true,
169+
},
170+
],
171+
},
172+
{
173+
code: `
174+
export const f = (a: any, b: number) => a + b;
175+
`,
176+
options: [
177+
{
178+
allowAny: true,
179+
},
180+
],
181+
},
142182
],
143183
invalid: [
144184
{
@@ -515,7 +555,7 @@ function foo<T extends 1>(a: T) {
515555
`,
516556
errors: [
517557
{
518-
messageId: 'notStrings',
558+
messageId: 'notNumbers',
519559
line: 4,
520560
column: 19,
521561
},
@@ -571,5 +611,125 @@ foo += 0;
571611
},
572612
],
573613
},
614+
{
615+
code: `
616+
const f = (a: any, b: boolean) => a + b;
617+
`,
618+
options: [
619+
{
620+
allowAny: true,
621+
},
622+
],
623+
errors: [
624+
{
625+
messageId: 'notNumbers',
626+
line: 2,
627+
column: 35,
628+
},
629+
],
630+
},
631+
{
632+
code: `
633+
const f = (a: any, b: []) => a + b;
634+
`,
635+
options: [
636+
{
637+
allowAny: true,
638+
},
639+
],
640+
errors: [
641+
{
642+
messageId: 'notNumbers',
643+
line: 2,
644+
column: 30,
645+
},
646+
],
647+
},
648+
649+
{
650+
code: `
651+
const f = (a: any, b: any) => a + b;
652+
`,
653+
options: [
654+
{
655+
allowAny: false,
656+
},
657+
],
658+
errors: [
659+
{
660+
messageId: 'notNumbers',
661+
line: 2,
662+
column: 31,
663+
},
664+
],
665+
},
666+
{
667+
code: `
668+
const f = (a: any, b: string) => a + b;
669+
`,
670+
options: [
671+
{
672+
allowAny: false,
673+
},
674+
],
675+
errors: [
676+
{
677+
messageId: 'notNumbers',
678+
line: 2,
679+
column: 34,
680+
},
681+
],
682+
},
683+
{
684+
code: `
685+
const f = (a: any, b: bigint) => a + b;
686+
`,
687+
options: [
688+
{
689+
allowAny: false,
690+
},
691+
],
692+
errors: [
693+
{
694+
messageId: 'notNumbers',
695+
line: 2,
696+
column: 34,
697+
},
698+
],
699+
},
700+
{
701+
code: `
702+
const f = (a: any, b: number) => a + b;
703+
`,
704+
options: [
705+
{
706+
allowAny: false,
707+
},
708+
],
709+
errors: [
710+
{
711+
messageId: 'notNumbers',
712+
line: 2,
713+
column: 34,
714+
},
715+
],
716+
},
717+
{
718+
code: `
719+
const f = (a: any, b: boolean) => a + b;
720+
`,
721+
options: [
722+
{
723+
allowAny: false,
724+
},
725+
],
726+
errors: [
727+
{
728+
messageId: 'notNumbers',
729+
line: 2,
730+
column: 35,
731+
},
732+
],
733+
},
574734
],
575735
});

0 commit comments

Comments
 (0)