@typescript-eslint/eslint-plugin 6.0.0-alpha.99 → 6.0.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.
Files changed (195) hide show
  1. package/README.md +2 -0
  2. package/dist/configs/all.js +2 -0
  3. package/dist/configs/all.js.map +1 -1
  4. package/dist/configs/disable-type-checked.js +3 -0
  5. package/dist/configs/disable-type-checked.js.map +1 -1
  6. package/dist/configs/recommended-type-checked.js +6 -0
  7. package/dist/configs/recommended-type-checked.js.map +1 -1
  8. package/dist/configs/recommended.js +2 -0
  9. package/dist/configs/recommended.js.map +1 -1
  10. package/dist/configs/strict-type-checked.js +4 -0
  11. package/dist/configs/strict-type-checked.js.map +1 -1
  12. package/dist/configs/stylistic-type-checked.js +0 -1
  13. package/dist/configs/stylistic-type-checked.js.map +1 -1
  14. package/dist/configs/stylistic.js +0 -2
  15. package/dist/configs/stylistic.js.map +1 -1
  16. package/dist/index.js +1 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/rules/array-type.js +19 -20
  19. package/dist/rules/array-type.js.map +1 -1
  20. package/dist/rules/ban-ts-comment.js +33 -35
  21. package/dist/rules/ban-ts-comment.js.map +1 -1
  22. package/dist/rules/ban-types.js +75 -14
  23. package/dist/rules/ban-types.js.map +1 -1
  24. package/dist/rules/class-literal-property-style.js +38 -21
  25. package/dist/rules/class-literal-property-style.js.map +1 -1
  26. package/dist/rules/comma-dangle.js +4 -2
  27. package/dist/rules/comma-dangle.js.map +1 -1
  28. package/dist/rules/comma-spacing.js +5 -0
  29. package/dist/rules/comma-spacing.js.map +1 -1
  30. package/dist/rules/consistent-generic-constructors.js +1 -0
  31. package/dist/rules/consistent-generic-constructors.js.map +1 -1
  32. package/dist/rules/consistent-indexed-object-style.js +1 -0
  33. package/dist/rules/consistent-indexed-object-style.js.map +1 -1
  34. package/dist/rules/consistent-type-assertions.js +49 -0
  35. package/dist/rules/consistent-type-assertions.js.map +1 -1
  36. package/dist/rules/consistent-type-definitions.js +1 -0
  37. package/dist/rules/consistent-type-definitions.js.map +1 -1
  38. package/dist/rules/consistent-type-exports.js +1 -0
  39. package/dist/rules/consistent-type-exports.js.map +1 -1
  40. package/dist/rules/consistent-type-imports.js +2 -0
  41. package/dist/rules/consistent-type-imports.js.map +1 -1
  42. package/dist/rules/enum-utils/shared.js +61 -0
  43. package/dist/rules/enum-utils/shared.js.map +1 -0
  44. package/dist/rules/explicit-function-return-type.js.map +1 -1
  45. package/dist/rules/explicit-member-accessibility.js +43 -44
  46. package/dist/rules/explicit-member-accessibility.js.map +1 -1
  47. package/dist/rules/explicit-module-boundary-types.js +1 -1
  48. package/dist/rules/explicit-module-boundary-types.js.map +1 -1
  49. package/dist/rules/func-call-spacing.js +2 -0
  50. package/dist/rules/func-call-spacing.js.map +1 -1
  51. package/dist/rules/indent.js.map +1 -1
  52. package/dist/rules/index.js +4 -0
  53. package/dist/rules/index.js.map +1 -1
  54. package/dist/rules/key-spacing.js.map +1 -1
  55. package/dist/rules/keyword-spacing.js.map +1 -1
  56. package/dist/rules/lines-around-comment.js +78 -81
  57. package/dist/rules/lines-around-comment.js.map +1 -1
  58. package/dist/rules/lines-between-class-members.js +7 -5
  59. package/dist/rules/lines-between-class-members.js.map +1 -1
  60. package/dist/rules/member-delimiter-style.js +45 -27
  61. package/dist/rules/member-delimiter-style.js.map +1 -1
  62. package/dist/rules/member-ordering.js +55 -66
  63. package/dist/rules/member-ordering.js.map +1 -1
  64. package/dist/rules/method-signature-style.js +1 -0
  65. package/dist/rules/method-signature-style.js.map +1 -1
  66. package/dist/rules/naming-convention-utils/enums.js +6 -12
  67. package/dist/rules/naming-convention-utils/enums.js.map +1 -1
  68. package/dist/rules/naming-convention-utils/schema.js +50 -25
  69. package/dist/rules/naming-convention-utils/schema.js.map +1 -1
  70. package/dist/rules/naming-convention.js.map +1 -1
  71. package/dist/rules/no-base-to-string.js +2 -2
  72. package/dist/rules/no-base-to-string.js.map +1 -1
  73. package/dist/rules/no-confusing-void-expression.js +1 -0
  74. package/dist/rules/no-confusing-void-expression.js.map +1 -1
  75. package/dist/rules/no-duplicate-type-constituents.js +161 -0
  76. package/dist/rules/no-duplicate-type-constituents.js.map +1 -0
  77. package/dist/rules/no-empty-function.js +1 -0
  78. package/dist/rules/no-empty-function.js.map +1 -1
  79. package/dist/rules/no-empty-interface.js +2 -1
  80. package/dist/rules/no-empty-interface.js.map +1 -1
  81. package/dist/rules/no-explicit-any.js +1 -1
  82. package/dist/rules/no-explicit-any.js.map +1 -1
  83. package/dist/rules/no-extraneous-class.js +2 -3
  84. package/dist/rules/no-extraneous-class.js.map +1 -1
  85. package/dist/rules/no-implied-eval.js +1 -0
  86. package/dist/rules/no-implied-eval.js.map +1 -1
  87. package/dist/rules/no-inferrable-types.js.map +1 -1
  88. package/dist/rules/no-invalid-void-type.js +1 -1
  89. package/dist/rules/no-invalid-void-type.js.map +1 -1
  90. package/dist/rules/no-loop-func.js.map +1 -1
  91. package/dist/rules/no-magic-numbers.js.map +1 -1
  92. package/dist/rules/no-misused-promises.js +3 -2
  93. package/dist/rules/no-misused-promises.js.map +1 -1
  94. package/dist/rules/no-redeclare.js +2 -1
  95. package/dist/rules/no-redeclare.js.map +1 -1
  96. package/dist/rules/no-redundant-type-constituents.js +2 -0
  97. package/dist/rules/no-redundant-type-constituents.js.map +1 -1
  98. package/dist/rules/no-restricted-imports.js +80 -21
  99. package/dist/rules/no-restricted-imports.js.map +1 -1
  100. package/dist/rules/no-shadow.js +2 -1
  101. package/dist/rules/no-shadow.js.map +1 -1
  102. package/dist/rules/no-type-alias.js +24 -15
  103. package/dist/rules/no-type-alias.js.map +1 -1
  104. package/dist/rules/no-unnecessary-condition.js +2 -2
  105. package/dist/rules/no-unnecessary-condition.js.map +1 -1
  106. package/dist/rules/no-unnecessary-qualifier.js.map +1 -1
  107. package/dist/rules/no-unnecessary-type-assertion.js +1 -0
  108. package/dist/rules/no-unnecessary-type-assertion.js.map +1 -1
  109. package/dist/rules/no-unsafe-argument.js +3 -3
  110. package/dist/rules/no-unsafe-argument.js.map +1 -1
  111. package/dist/rules/no-unsafe-declaration-merging.js +1 -1
  112. package/dist/rules/no-unsafe-declaration-merging.js.map +1 -1
  113. package/dist/rules/no-unsafe-enum-comparison.js +119 -0
  114. package/dist/rules/no-unsafe-enum-comparison.js.map +1 -0
  115. package/dist/rules/no-unused-vars.js +4 -0
  116. package/dist/rules/no-unused-vars.js.map +1 -1
  117. package/dist/rules/no-use-before-define.js +1 -0
  118. package/dist/rules/no-use-before-define.js.map +1 -1
  119. package/dist/rules/padding-line-between-statements.js +11 -3
  120. package/dist/rules/padding-line-between-statements.js.map +1 -1
  121. package/dist/rules/parameter-properties.js +29 -30
  122. package/dist/rules/parameter-properties.js.map +1 -1
  123. package/dist/rules/prefer-includes.js +21 -5
  124. package/dist/rules/prefer-includes.js.map +1 -1
  125. package/dist/rules/prefer-nullish-coalescing.js +82 -63
  126. package/dist/rules/prefer-nullish-coalescing.js.map +1 -1
  127. package/dist/rules/prefer-optional-chain-utils/PreferOptionalChainOptions.js +3 -0
  128. package/dist/rules/prefer-optional-chain-utils/PreferOptionalChainOptions.js.map +1 -0
  129. package/dist/rules/prefer-optional-chain-utils/analyzeChain.js +419 -0
  130. package/dist/rules/prefer-optional-chain-utils/analyzeChain.js.map +1 -0
  131. package/dist/rules/prefer-optional-chain-utils/compareNodes.js +318 -0
  132. package/dist/rules/prefer-optional-chain-utils/compareNodes.js.map +1 -0
  133. package/dist/rules/prefer-optional-chain-utils/gatherLogicalOperands.js +281 -0
  134. package/dist/rules/prefer-optional-chain-utils/gatherLogicalOperands.js.map +1 -0
  135. package/dist/rules/prefer-optional-chain.js +80 -391
  136. package/dist/rules/prefer-optional-chain.js.map +1 -1
  137. package/dist/rules/prefer-readonly.js +1 -1
  138. package/dist/rules/prefer-readonly.js.map +1 -1
  139. package/dist/rules/prefer-regexp-exec.js +7 -1
  140. package/dist/rules/prefer-regexp-exec.js.map +1 -1
  141. package/dist/rules/require-array-sort-compare.js +3 -2
  142. package/dist/rules/require-array-sort-compare.js.map +1 -1
  143. package/dist/rules/restrict-plus-operands.js +132 -96
  144. package/dist/rules/restrict-plus-operands.js.map +1 -1
  145. package/dist/rules/restrict-template-expressions.js +11 -6
  146. package/dist/rules/restrict-template-expressions.js.map +1 -1
  147. package/dist/rules/return-await.js +1 -0
  148. package/dist/rules/return-await.js.map +1 -1
  149. package/dist/rules/sort-type-constituents.js +1 -1
  150. package/dist/rules/sort-type-constituents.js.map +1 -1
  151. package/dist/rules/space-before-function-paren.js +4 -0
  152. package/dist/rules/space-before-function-paren.js.map +1 -1
  153. package/dist/rules/strict-boolean-expressions.js +7 -2
  154. package/dist/rules/strict-boolean-expressions.js.map +1 -1
  155. package/dist/rules/switch-exhaustiveness-check.js.map +1 -1
  156. package/dist/rules/triple-slash-reference.js +3 -0
  157. package/dist/rules/triple-slash-reference.js.map +1 -1
  158. package/dist/rules/type-annotation-spacing.js +16 -14
  159. package/dist/rules/type-annotation-spacing.js.map +1 -1
  160. package/dist/rules/typedef.js +1 -0
  161. package/dist/rules/typedef.js.map +1 -1
  162. package/dist/rules/unbound-method.js +1 -0
  163. package/dist/rules/unbound-method.js.map +1 -1
  164. package/dist/rules/unified-signatures.js +3 -3
  165. package/dist/rules/unified-signatures.js.map +1 -1
  166. package/dist/util/astUtils.js.map +1 -1
  167. package/dist/util/collectUnusedVariables.js +1 -1
  168. package/dist/util/collectUnusedVariables.js.map +1 -1
  169. package/dist/util/getOperatorPrecedence.js +112 -2
  170. package/dist/util/getOperatorPrecedence.js.map +1 -1
  171. package/dist/util/getStringLength.js +2 -2
  172. package/dist/util/getStringLength.js.map +1 -1
  173. package/dist/util/misc.js +1 -2
  174. package/dist/util/misc.js.map +1 -1
  175. package/docs/rules/README.md +2 -2
  176. package/docs/rules/ban-types.md +10 -0
  177. package/docs/rules/comma-dangle.md +1 -1
  178. package/docs/rules/explicit-module-boundary-types.md +1 -1
  179. package/docs/rules/lines-around-comment.md +3 -13
  180. package/docs/rules/naming-convention.md +63 -63
  181. package/docs/rules/no-duplicate-type-constituents.md +61 -0
  182. package/docs/rules/no-unnecessary-boolean-literal-compare.md +10 -10
  183. package/docs/rules/no-unnecessary-type-constraint.md +6 -2
  184. package/docs/rules/no-unsafe-enum-comparison.md +77 -0
  185. package/docs/rules/prefer-includes.md +1 -1
  186. package/docs/rules/prefer-nullish-coalescing.md +23 -0
  187. package/docs/rules/prefer-optional-chain.md +195 -4
  188. package/docs/rules/require-await.md +0 -2
  189. package/docs/rules/restrict-plus-operands.md +135 -25
  190. package/docs/rules/restrict-template-expressions.md +15 -3
  191. package/docs/rules/sort-type-constituents.md +3 -3
  192. package/docs/rules/triple-slash-reference.md +0 -2
  193. package/docs/rules/type-annotation-spacing.md +22 -8
  194. package/docs/rules/unified-signatures.md +0 -2
  195. package/package.json +22 -15
@@ -0,0 +1,61 @@
1
+ ---
2
+ description: 'Disallow duplicate constituents of union or intersection types.'
3
+ ---
4
+
5
+ > 🛑 This file is source code, not the primary documentation location! 🛑
6
+ >
7
+ > See **https://typescript-eslint.io/rules/no-duplicate-type-constituents** for documentation.
8
+
9
+ TypeScript supports types ("constituents") within union and intersection types being duplicates of each other.
10
+ However, developers typically expect each constituent to be unique within its intersection or union.
11
+ Duplicate values make the code overly verbose and generally reduce readability.
12
+
13
+ ## Rule Details
14
+
15
+ This rule disallows duplicate union or intersection constituents.
16
+ We consider types to be duplicate if they evaluate to the same result in the type system.
17
+ For example, given `type A = string` and `type T = string | A`, this rule would flag that `A` is the same type as `string`.
18
+
19
+ <!--tabs-->
20
+
21
+ ### ❌ Incorrect
22
+
23
+ ```ts
24
+ type T1 = 'A' | 'A';
25
+
26
+ type T2 = A | A | B;
27
+
28
+ type T3 = { a: string } & { a: string };
29
+
30
+ type T4 = [1, 2, 3] | [1, 2, 3];
31
+
32
+ type StringA = string;
33
+ type StringB = string;
34
+ type T5 = StringA | StringB;
35
+ ```
36
+
37
+ ### ✅ Correct
38
+
39
+ ```ts
40
+ type T1 = 'A' | 'B';
41
+
42
+ type T2 = A | B | C;
43
+
44
+ type T3 = { a: string } & { b: string };
45
+
46
+ type T4 = [1, 2, 3] | [1, 2, 3, 4];
47
+
48
+ type StringA = string;
49
+ type NumberB = number;
50
+ type T5 = StringA | NumberB;
51
+ ```
52
+
53
+ ## Options
54
+
55
+ ### `ignoreIntersections`
56
+
57
+ When set to true, duplicate checks on intersection type constituents are ignored.
58
+
59
+ ### `ignoreUnions`
60
+
61
+ When set to true, duplicate checks on union type constituents are ignored.
@@ -115,16 +115,16 @@ if (!(someNullCondition ?? true)) {
115
115
 
116
116
  ## Fixer
117
117
 
118
- | Comparison | Fixer Output | Notes |
119
- | :----------------------------: | ------------------------------- | ----------------------------------------------------------------------------------- |
120
- | `booleanVar === true` | `booleanVar` | |
121
- | `booleanVar !== true` | `!booleanVar` | |
122
- | `booleanVar === false` | `!booleanVar` | |
123
- | `booleanVar !== false` | `booleanVar` | |
124
- | `nullableBooleanVar === true` | `nullableBooleanVar` | Only checked/fixed if the `allowComparingNullableBooleansToTrue` option is `false` |
125
- | `nullableBooleanVar !== true` | `!nullableBooleanVar` | Only checked/fixed if the `allowComparingNullableBooleansToTrue` option is `false` |
126
- | `nullableBooleanVar === false` | `nullableBooleanVar ?? true` | Only checked/fixed if the `allowComparingNullableBooleansToFalse` option is `false` |
127
- | `nullableBooleanVar !== false` | `!(nullableBooleanVar ?? true)` | Only checked/fixed if the `allowComparingNullableBooleansToFalse` option is `false` |
118
+ | Comparison | Fixer Output | Notes |
119
+ | :-------------------------------: | ------------------------------- | ----------------------------------------------------------------------------------- |
120
+ | `booleanVar === true` | `booleanVar` | |
121
+ | `booleanVar !== true` | `!booleanVar` | |
122
+ | `booleanVar === false` | `!booleanVar` | |
123
+ | `booleanVar !== false` | `booleanVar` | |
124
+ | `nullableBooleanVar === true` | `nullableBooleanVar` | Only checked/fixed if the `allowComparingNullableBooleansToTrue` option is `false` |
125
+ | `nullableBooleanVar !== true` | `!nullableBooleanVar` | Only checked/fixed if the `allowComparingNullableBooleansToTrue` option is `false` |
126
+ | `!(nullableBooleanVar === false)` | `nullableBooleanVar ?? true` | Only checked/fixed if the `allowComparingNullableBooleansToFalse` option is `false` |
127
+ | `!(nullableBooleanVar !== false)` | `!(nullableBooleanVar ?? true)` | Only checked/fixed if the `allowComparingNullableBooleansToFalse` option is `false` |
128
128
 
129
129
  ## Not To Use It
130
130
 
@@ -7,8 +7,8 @@ description: 'Disallow unnecessary constraints on generic types.'
7
7
  > See **https://typescript-eslint.io/rules/no-unnecessary-type-constraint** for documentation.
8
8
 
9
9
  Generic type parameters (`<T>`) in TypeScript may be "constrained" with an [`extends` keyword](https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints).
10
- When no `extends` is provided, type parameters default a constraint to `any`.
11
- It is therefore redundant to `extend` from `any`.
10
+ When no `extends` is provided, type parameters default a constraint to `unknown`.
11
+ It is therefore redundant to `extend` from `any` or `unknown`.
12
12
 
13
13
  ## Examples
14
14
 
@@ -19,8 +19,12 @@ It is therefore redundant to `extend` from `any`.
19
19
  ```ts
20
20
  interface FooAny<T extends any> {}
21
21
 
22
+ interface FooUnknown<T extends unknown> {}
23
+
22
24
  type BarAny<T extends any> = {};
23
25
 
26
+ type BarUnknown<T extends unknown> = {};
27
+
24
28
  class BazAny<T extends any> {
25
29
  quxAny<U extends any>() {}
26
30
  }
@@ -0,0 +1,77 @@
1
+ ---
2
+ description: 'Disallow comparing an enum value with a non-enum value.'
3
+ ---
4
+
5
+ > 🛑 This file is source code, not the primary documentation location! 🛑
6
+ >
7
+ > See **https://typescript-eslint.io/rules/no-unsafe-enum-comparison** for documentation.
8
+
9
+ The TypeScript compiler can be surprisingly lenient when working with enums.
10
+ For example, it will allow you to compare enum values against numbers even though they might not have any type overlap:
11
+
12
+ ```ts
13
+ enum Fruit {
14
+ Apple,
15
+ Banana,
16
+ }
17
+
18
+ declare let fruit: Fruit;
19
+
20
+ fruit === 999; // No error
21
+ ```
22
+
23
+ This rule flags when an enum typed value is compared to a non-enum `number`.
24
+
25
+ ## Examples
26
+
27
+ <!--tabs-->
28
+
29
+ ### ❌ Incorrect
30
+
31
+ ```ts
32
+ enum Fruit {
33
+ Apple,
34
+ }
35
+
36
+ declare let fruit: Fruit;
37
+
38
+ fruit === 999;
39
+ ```
40
+
41
+ ```ts
42
+ enum Vegetable {
43
+ Asparagus = 'asparagus',
44
+ }
45
+
46
+ declare let vegetable: Vegetable;
47
+
48
+ vegetable === 'asparagus';
49
+ ```
50
+
51
+ ### ✅ Correct
52
+
53
+ ```ts
54
+ enum Fruit {
55
+ Apple,
56
+ }
57
+
58
+ declare let fruit: Fruit;
59
+
60
+ fruit === Fruit.Banana;
61
+ ```
62
+
63
+ ```ts
64
+ enum Vegetable {
65
+ Asparagus = 'asparagus',
66
+ }
67
+
68
+ declare let vegetable: Vegetable;
69
+
70
+ vegetable === Vegetable.Asparagus;
71
+ ```
72
+
73
+ <!--/tabs-->
74
+
75
+ ## When Not To Use It
76
+
77
+ If you don't mind number and/or literal string constants being compared against enums, you likely don't need this rule.
@@ -57,7 +57,7 @@ const userDefined: {
57
57
 
58
58
  str.includes(value);
59
59
  array.includes(value);
60
- readonlyArray.includes(value);
60
+ !readonlyArray.includes(value);
61
61
  typedArray.includes(value);
62
62
  maybe?.includes('');
63
63
  userDefined.includes(value);
@@ -142,6 +142,29 @@ a ?? (b && c && d);
142
142
 
143
143
  **_NOTE:_** Errors for this specific case will be presented as suggestions (see below), instead of fixes. This is because it is not always safe to automatically convert `||` to `??` within a mixed logical expression, as we cannot tell the intended precedence of the operator. Note that by design, `??` requires parentheses when used with `&&` or `||` in the same expression.
144
144
 
145
+ ### `ignorePrimitives`
146
+
147
+ If you would like to ignore certain primitive types that can be falsy then you may pass an object containing a boolean value for each primitive:
148
+
149
+ - `string: true`, ignores `null` or `undefined` unions with `string` (default: false).
150
+ - `number: true`, ignores `null` or `undefined` unions with `number` (default: false).
151
+ - `bigint: true`, ignores `null` or `undefined` unions with `bigint` (default: false).
152
+ - `boolean: true`, ignores `null` or `undefined` unions with `boolean` (default: false).
153
+
154
+ Incorrect code for `ignorePrimitives: { string: true }`, and correct code for `ignorePrimitives: { string: false }`:
155
+
156
+ ```ts
157
+ const foo: string | undefined = 'bar';
158
+ foo || 'a string';
159
+ ```
160
+
161
+ Correct code for `ignorePrimitives: { string: true }`:
162
+
163
+ ```ts
164
+ const foo: string | undefined = 'bar';
165
+ foo ?? 'a string';
166
+ ```
167
+
145
168
  ## When Not To Use It
146
169
 
147
170
  If you are not using TypeScript 3.7 (or greater), then you will not be able to use this rule, as the operator is not supported.
@@ -57,13 +57,204 @@ foo?.a?.b?.c?.d?.e;
57
57
 
58
58
  <!--/tabs-->
59
59
 
60
- :::note
61
- There are a few edge cases where this rule will false positive. Use your best judgement when evaluating reported errors.
62
- :::
60
+ ## Options
61
+
62
+ In the context of the descriptions below a "loose boolean" operand is any operand that implicitly coerces the value to a boolean.
63
+ Specifically the argument of the not operator (`!loose`) or a bare value in a logical expression (`loose && looser`).
64
+
65
+ ### `allowPotentiallyUnsafeFixesThatModifyTheReturnTypeIKnowWhatImDoing`
66
+
67
+ When this option is `true`, the rule will not provide an auto-fixer for cases where the return type of the expression would change. For example for the expression `!foo || foo.bar` the return type of the expression is `true | T`, however for the equivalent optional chain `foo?.bar` the return type of the expression is `undefined | T`. Thus changing the code from a logical expression to an optional chain expression has altered the type of the expression.
68
+
69
+ In some cases this distinction _may_ matter - which is why these fixers are considered unsafe - they may break the build! For example in the following code:
70
+
71
+ ```ts
72
+ declare const foo: { bar: boolean } | null | undefined;
73
+ declare function acceptsBoolean(arg: boolean): void;
74
+
75
+ // ✅ typechecks succesfully as the expression only returns `boolean`
76
+ acceptsBoolean(foo != null && foo.bar);
77
+
78
+ // ❌ typechecks UNSUCCESSFULLY as the expression returns `boolean | undefined`
79
+ acceptsBoolean(foo != null && foo.bar);
80
+ ```
81
+
82
+ This style of code isn't super common - which means having this option set to `true` _should_ be safe in most codebases. However we default it to `false` due to its unsafe nature. We have provided this option for convenience because it increases the autofix cases covered by the rule. If you set option to `true` the onus is entirely on you and your team to ensure that each fix is correct and safe and that it does not break the build.
83
+
84
+ When this option is `false` unsafe cases will have suggestion fixers provided instead of auto-fixers - meaning you can manually apply the fix using your IDE tooling.
85
+
86
+ ### `checkAny`
87
+
88
+ When this option is `true` the rule will check operands that are typed as `any` when inspecting "loose boolean" operands.
89
+
90
+ <!--tabs-->
91
+
92
+ #### ❌ Incorrect for `checkAny: true`
93
+
94
+ ```ts
95
+ declare const thing: any;
96
+
97
+ thing && thing.toString();
98
+ ```
99
+
100
+ #### ✅ Correct for `checkAny: false`
101
+
102
+ ```ts
103
+ declare const thing: any;
104
+
105
+ thing && thing.toString();
106
+ ```
107
+
108
+ <!--/tabs-->
109
+
110
+ ### `checkUnknown`
111
+
112
+ When this option is `true` the rule will check operands that are typed as `unknown` when inspecting "loose boolean" operands.
113
+
114
+ <!--tabs-->
115
+
116
+ #### ❌ Incorrect for `checkUnknown: true`
117
+
118
+ ```ts
119
+ declare const thing: unknown;
120
+
121
+ thing && thing.toString();
122
+ ```
123
+
124
+ #### ✅ Correct for `checkUnknown: false`
125
+
126
+ ```ts
127
+ declare const thing: unknown;
128
+
129
+ thing && thing.toString();
130
+ ```
131
+
132
+ <!--/tabs-->
133
+
134
+ ### `checkString`
135
+
136
+ When this option is `true` the rule will check operands that are typed as `string` when inspecting "loose boolean" operands.
137
+
138
+ <!--tabs-->
139
+
140
+ #### ❌ Incorrect for `checkString: true`
141
+
142
+ ```ts
143
+ declare const thing: string;
144
+
145
+ thing && thing.toString();
146
+ ```
147
+
148
+ #### ✅ Correct for `checkString: false`
149
+
150
+ ```ts
151
+ declare const thing: string;
152
+
153
+ thing && thing.toString();
154
+ ```
155
+
156
+ <!--/tabs-->
157
+
158
+ ### `checkNumber`
159
+
160
+ When this option is `true` the rule will check operands that are typed as `number` when inspecting "loose boolean" operands.
161
+
162
+ <!--tabs-->
163
+
164
+ #### ❌ Incorrect for `checkNumber: true`
165
+
166
+ ```ts
167
+ declare const thing: number;
168
+
169
+ thing && thing.toString();
170
+ ```
171
+
172
+ #### ✅ Correct for `checkNumber: false`
173
+
174
+ ```ts
175
+ declare const thing: number;
176
+
177
+ thing && thing.toString();
178
+ ```
179
+
180
+ <!--/tabs-->
181
+
182
+ ### `checkBoolean`
183
+
184
+ When this option is `true` the rule will check operands that are typed as `boolean` when inspecting "loose boolean" operands.
185
+
186
+ <!--tabs-->
187
+
188
+ #### ❌ Incorrect for `checkBoolean: true`
189
+
190
+ ```ts
191
+ declare const thing: boolean;
192
+
193
+ thing && thing.toString();
194
+ ```
195
+
196
+ #### ✅ Correct for `checkBoolean: false`
197
+
198
+ ```ts
199
+ declare const thing: boolean;
200
+
201
+ thing && thing.toString();
202
+ ```
203
+
204
+ <!--/tabs-->
205
+
206
+ ### `checkBigInt`
207
+
208
+ When this option is `true` the rule will check operands that are typed as `bigint` when inspecting "loose boolean" operands.
209
+
210
+ <!--tabs-->
211
+
212
+ #### ❌ Incorrect for `checkBigInt: true`
213
+
214
+ ```ts
215
+ declare const thing: bigint;
216
+
217
+ thing && thing.toString();
218
+ ```
219
+
220
+ #### ✅ Correct for `checkBigInt: false`
221
+
222
+ ```ts
223
+ declare const thing: bigint;
224
+
225
+ thing && thing.toString();
226
+ ```
227
+
228
+ <!--/tabs-->
229
+
230
+ ### `requireNullish`
231
+
232
+ When this option is `true` the rule will skip operands that are not typed with `null` and/or `undefined` when inspecting "loose boolean" operands.
233
+
234
+ <!--tabs-->
235
+
236
+ #### ❌ Incorrect for `requireNullish: true`
237
+
238
+ ```ts
239
+ declare const thing1: string | null;
240
+ thing1 && thing1.toString();
241
+ ```
242
+
243
+ #### ✅ Correct for `requireNullish: true`
244
+
245
+ ```ts
246
+ declare const thing1: string | null;
247
+ thing1?.toString();
248
+
249
+ declare const thing2: string;
250
+ thing2 && thing2.toString();
251
+ ```
252
+
253
+ <!--/tabs-->
63
254
 
64
255
  ## When Not To Use It
65
256
 
66
- If you don't mind using more explicit `&&`s, you don't need this rule.
257
+ If you don't mind using more explicit `&&`s/`||`s, you don't need this rule.
67
258
 
68
259
  ## Further Reading
69
260
 
@@ -20,5 +20,3 @@ async function returnsPromise1() {
20
20
 
21
21
  const returnsPromise2 = () => returnsPromise1();
22
22
  ```
23
-
24
- ## How to Use
@@ -18,70 +18,180 @@ This rule reports when a `+` operation combines two values of different types, o
18
18
  ### ❌ Incorrect
19
19
 
20
20
  ```ts
21
- var foo = '5.5' + 5;
22
- var foo = 1n + 1;
21
+ let foo = '5.5' + 5;
22
+ let foo = 1n + 1;
23
23
  ```
24
24
 
25
25
  ### ✅ Correct
26
26
 
27
27
  ```ts
28
- var foo = parseInt('5.5', 10) + 10;
29
- var foo = 1n + 1n;
28
+ let foo = parseInt('5.5', 10) + 10;
29
+ let foo = 1n + 1n;
30
30
  ```
31
31
 
32
32
  ## Options
33
33
 
34
- ### `checkCompoundAssignments`
34
+ :::caution
35
+ We generally recommend against using these options, as they limit which varieties of incorrect `+` usage can be checked.
36
+ This in turn severely limits the validation that the rule can do to ensure that resulting strings and numbers are correct.
37
+
38
+ Safer alternatives to using the `allow*` options include:
39
+
40
+ - Using variadic forms of logging APIs to avoid needing to `+` values.
41
+ ```ts
42
+ // Remove this line
43
+ console.log('The result is ' + true);
44
+ // Add this line
45
+ console.log('The result is', true);
46
+ ```
47
+ - Using `.toFixed()` to coerce numbers to well-formed string representations:
48
+ ```ts
49
+ const number = 1.123456789;
50
+ const result = 'The number is ' + number.toFixed(2);
51
+ // result === 'The number is 1.12'
52
+ ```
53
+ - Calling `.toString()` on other types to mark explicit and intentional string coercion:
54
+ ```ts
55
+ const arg = '11';
56
+ const regex = /[0-9]/;
57
+ const result =
58
+ 'The result of ' +
59
+ regex.toString() +
60
+ '.test("' +
61
+ arg +
62
+ '") is ' +
63
+ regex.test(arg).toString();
64
+ // result === 'The result of /[0-9]/.test("11") is true'
65
+ ```
66
+
67
+ :::
35
68
 
36
- Examples of code for this rule with `{ checkCompoundAssignments: true }`:
69
+ ### `allowAny`
70
+
71
+ Examples of code for this rule with `{ allowAny: true }`:
37
72
 
38
73
  <!--tabs-->
39
74
 
40
75
  #### ❌ Incorrect
41
76
 
42
77
  ```ts
43
- /*eslint @typescript-eslint/restrict-plus-operands: ["error", { "checkCompoundAssignments": true }]*/
78
+ let fn = (a: number, b: []) => a + b;
79
+ let fn = (a: string, b: []) => a + b;
80
+ ```
44
81
 
45
- let foo: string | undefined;
46
- foo += 'some data';
82
+ #### ✅ Correct
47
83
 
48
- let bar: string = '';
49
- bar += 0;
84
+ ```ts
85
+ let fn = (a: number, b: any) => a + b;
86
+ let fn = (a: string, b: any) => a + b;
87
+ ```
88
+
89
+ ### `allowBoolean`
90
+
91
+ Examples of code for this rule with `{ allowBoolean: true }`:
92
+
93
+ <!--tabs-->
94
+
95
+ #### ❌ Incorrect
96
+
97
+ ```ts
98
+ let fn = (a: number, b: unknown) => a + b;
99
+ let fn = (a: string, b: unknown) => a + b;
50
100
  ```
51
101
 
52
102
  #### ✅ Correct
53
103
 
54
104
  ```ts
55
- /*eslint @typescript-eslint/restrict-plus-operands: ["error", { "checkCompoundAssignments": true }]*/
105
+ let fn = (a: number, b: boolean) => a + b;
106
+ let fn = (a: string, b: boolean) => a + b;
107
+ ```
56
108
 
57
- let foo: number = 0;
58
- foo += 1;
109
+ ### `allowNullish`
59
110
 
60
- let bar = '';
61
- bar += 'test';
111
+ Examples of code for this rule with `{ allowNullish: true }`:
112
+
113
+ <!--tabs-->
114
+
115
+ #### ❌ Incorrect
116
+
117
+ ```ts
118
+ let fn = (a: number, b: unknown) => a + b;
119
+ let fn = (a: number, b: never) => a + b;
120
+ let fn = (a: string, b: unknown) => a + b;
121
+ let fn = (a: string, b: never) => a + b;
62
122
  ```
63
123
 
64
- ### `allowAny`
124
+ #### ✅ Correct
65
125
 
66
- Examples of code for this rule with `{ allowAny: true }`:
126
+ ```ts
127
+ let fn = (a: number, b: undefined) => a + b;
128
+ let fn = (a: number, b: null) => a + b;
129
+ let fn = (a: string, b: undefined) => a + b;
130
+ let fn = (a: string, b: null) => a + b;
131
+ ```
132
+
133
+ ### `allowNumberAndString`
134
+
135
+ Examples of code for this rule with `{ allowNumberAndString: true }`:
67
136
 
68
137
  <!--tabs-->
69
138
 
70
139
  #### ❌ Incorrect
71
140
 
72
141
  ```ts
73
- var fn = (a: any, b: boolean) => a + b;
74
- var fn = (a: any, b: []) => a + b;
75
- var fn = (a: any, b: {}) => a + b;
142
+ let fn = (a: number, b: unknown) => a + b;
143
+ let fn = (a: number, b: never) => a + b;
76
144
  ```
77
145
 
78
146
  #### ✅ Correct
79
147
 
80
148
  ```ts
81
- var fn = (a: any, b: any) => a + b;
82
- var fn = (a: any, b: string) => a + b;
83
- var fn = (a: any, b: bigint) => a + b;
84
- var fn = (a: any, b: number) => a + b;
149
+ let fn = (a: number, b: string) => a + b;
150
+ let fn = (a: number, b: number | string) => a + b;
151
+ ```
152
+
153
+ ### `allowRegExp`
154
+
155
+ Examples of code for this rule with `{ allowRegExp: true }`:
156
+
157
+ <!--tabs-->
158
+
159
+ #### ❌ Incorrect
160
+
161
+ ```ts
162
+ let fn = (a: number, b: RegExp) => a + b;
163
+ ```
164
+
165
+ #### ✅ Correct
166
+
167
+ ```ts
168
+ let fn = (a: string, b: RegExp) => a + b;
169
+ ```
170
+
171
+ ### `skipCompoundAssignments`
172
+
173
+ Examples of code for this rule with `{ skipCompoundAssignments: true }`:
174
+
175
+ <!--tabs-->
176
+
177
+ #### ❌ Incorrect
178
+
179
+ ```ts
180
+ let foo: string | undefined;
181
+ foo += 'some data';
182
+
183
+ let bar: string = '';
184
+ bar += 0;
185
+ ```
186
+
187
+ #### ✅ Correct
188
+
189
+ ```ts
190
+ let foo: number = 0;
191
+ foo += 1;
192
+
193
+ let bar = '';
194
+ bar += 'test';
85
195
  ```
86
196
 
87
197
  ## When Not To Use It
@@ -6,9 +6,19 @@ description: 'Enforce template literal expressions to be of `string` type.'
6
6
  >
7
7
  > See **https://typescript-eslint.io/rules/restrict-template-expressions** for documentation.
8
8
 
9
- JavaScript will call `toString()` on an object when it is converted to a string, such as when `+` adding to a string or in `${}` template literals.
10
- The default Object `.toString()` returns `"[object Object]"`, which is often not what was intended.
11
- This rule reports on values used in a template literal string that aren't primitives and don't define a more useful `.toString()` method.
9
+ JavaScript automatically [converts an object to a string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion) in a string context, such as when concatenating it with a string using `+` or embedding it in a template literal using `${}`.
10
+ The default `toString()` method of objects returns `"[object Object]"`, which is often not what was intended.
11
+ This rule reports on values used in a template literal string that aren't strings, numbers, or BigInts, optionally allowing other data types that provide useful stringification results.
12
+
13
+ :::note
14
+
15
+ This rule intentionally does not allow objects with a custom `toString()` method to be used in template literals, because the stringification result may not be user-friendly.
16
+
17
+ For example, arrays have a custom [`toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString) method, which only calls `join()` internally, which joins the array elements with commas. This means that (1) array elements are not necessarily stringified to useful results (2) the commas don't have spaces after them, making the result not user-friendly. The best way to format arrays is to use [`Intl.ListFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat), which even supports adding the "and" conjunction where necessary.
18
+ You must explicitly call `object.toString()` if you want to use this object in a template literal.
19
+ The [`no-base-to-string`](./no-base-to-string.md) rule can be used to guard this case against producing `"[object Object]"` by accident.
20
+
21
+ :::
12
22
 
13
23
  ## Examples
14
24
 
@@ -47,6 +57,8 @@ const msg1 = `arg = ${arg}`;
47
57
  const msg2 = `arg = ${arg || 'zero'}`;
48
58
  ```
49
59
 
60
+ This option controls both numbers and BigInts.
61
+
50
62
  ### `allowBoolean`
51
63
 
52
64
  Examples of additional **correct** code for this rule with `{ allowBoolean: true }`: