@depup/typescript-eslint__eslint-plugin 8.70.1-depup.0 → 8.71.0-depup.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 (36) hide show
  1. package/README.md +3 -3
  2. package/changes.json +2 -2
  3. package/dist/configs/eslintrc/all.d.ts +1 -0
  4. package/dist/configs/eslintrc/all.js +1 -0
  5. package/dist/configs/eslintrc/disable-type-checked.d.ts +1 -0
  6. package/dist/configs/eslintrc/disable-type-checked.js +1 -0
  7. package/dist/configs/eslintrc/strict-type-checked-only.d.ts +1 -0
  8. package/dist/configs/eslintrc/strict-type-checked-only.js +1 -0
  9. package/dist/configs/eslintrc/strict-type-checked.d.ts +1 -0
  10. package/dist/configs/eslintrc/strict-type-checked.js +1 -0
  11. package/dist/configs/flat/all.js +1 -0
  12. package/dist/configs/flat/disable-type-checked.js +1 -0
  13. package/dist/configs/flat/strict-type-checked-only.js +1 -0
  14. package/dist/configs/flat/strict-type-checked.js +1 -0
  15. package/dist/index.d.ts +7 -0
  16. package/dist/raw-plugin.d.ts +7 -0
  17. package/dist/rules/enum-utils/shared.d.ts +4 -0
  18. package/dist/rules/enum-utils/shared.js +1 -0
  19. package/dist/rules/index.d.ts +3 -0
  20. package/dist/rules/index.js +2 -0
  21. package/dist/rules/no-misused-promises.js +6 -1
  22. package/dist/rules/no-redundant-type-constituents.js +3 -1
  23. package/dist/rules/no-unnecessary-condition.js +1 -0
  24. package/dist/rules/no-unnecessary-type-assertion.d.ts +1 -1
  25. package/dist/rules/no-unnecessary-type-assertion.js +35 -5
  26. package/dist/rules/no-unnecessary-type-constraint.js +1 -0
  27. package/dist/rules/no-unsafe-enum-assignment.d.ts +5 -0
  28. package/dist/rules/no-unsafe-enum-assignment.js +473 -0
  29. package/dist/rules/prefer-nullish-coalescing.js +2 -3
  30. package/dist/rules/prefer-optional-chain-utils/analyzeChain.js +13 -4
  31. package/dist/rules/prefer-optional-chain-utils/gatherLogicalOperands.js +1 -0
  32. package/dist/rules/strict-void-return.js +2 -0
  33. package/dist/rules/switch-exhaustiveness-check.js +1 -1
  34. package/dist/rules/unbound-method.js +6 -12
  35. package/dist/util/getOperatorPrecedence.js +1 -0
  36. package/package.json +12 -12
package/README.md CHANGED
@@ -13,8 +13,8 @@ npm install @depup/typescript-eslint__eslint-plugin
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [@typescript-eslint/eslint-plugin](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin) @ 8.70.1 |
17
- | Processed | 2026-09-22 |
16
+ | Original | [@typescript-eslint/eslint-plugin](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin) @ 8.71.0 |
17
+ | Processed | 2026-09-29 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 1 |
20
20
 
@@ -22,7 +22,7 @@ npm install @depup/typescript-eslint__eslint-plugin
22
22
 
23
23
  | Dependency | From | To |
24
24
  |------------|------|-----|
25
- | ignore | ^7.0.5 | ^7.0.9 |
25
+ | ignore | ^7.0.5 | ^7.0.10 |
26
26
 
27
27
  ---
28
28
 
package/changes.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "bumped": {
3
3
  "ignore": {
4
4
  "from": "^7.0.5",
5
- "to": "^7.0.9"
5
+ "to": "^7.0.10"
6
6
  }
7
7
  },
8
- "timestamp": "2026-09-22T00:32:40.856Z",
8
+ "timestamp": "2026-09-29T00:34:06.060Z",
9
9
  "totalUpdated": 1
10
10
  }
@@ -92,6 +92,7 @@ declare const _default: {
92
92
  '@typescript-eslint/no-unsafe-assignment': "error";
93
93
  '@typescript-eslint/no-unsafe-call': "error";
94
94
  '@typescript-eslint/no-unsafe-declaration-merging': "error";
95
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
95
96
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
96
97
  '@typescript-eslint/no-unsafe-function-type': "error";
97
98
  '@typescript-eslint/no-unsafe-member-access': "error";
@@ -99,6 +99,7 @@ module.exports = {
99
99
  '@typescript-eslint/no-unsafe-assignment': 'error',
100
100
  '@typescript-eslint/no-unsafe-call': 'error',
101
101
  '@typescript-eslint/no-unsafe-declaration-merging': 'error',
102
+ '@typescript-eslint/no-unsafe-enum-assignment': 'error',
102
103
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
103
104
  '@typescript-eslint/no-unsafe-function-type': 'error',
104
105
  '@typescript-eslint/no-unsafe-member-access': 'error',
@@ -35,6 +35,7 @@ declare const _default: {
35
35
  '@typescript-eslint/no-unsafe-argument': "off";
36
36
  '@typescript-eslint/no-unsafe-assignment': "off";
37
37
  '@typescript-eslint/no-unsafe-call': "off";
38
+ '@typescript-eslint/no-unsafe-enum-assignment': "off";
38
39
  '@typescript-eslint/no-unsafe-enum-comparison': "off";
39
40
  '@typescript-eslint/no-unsafe-member-access': "off";
40
41
  '@typescript-eslint/no-unsafe-return': "off";
@@ -38,6 +38,7 @@ module.exports = {
38
38
  '@typescript-eslint/no-unsafe-argument': 'off',
39
39
  '@typescript-eslint/no-unsafe-assignment': 'off',
40
40
  '@typescript-eslint/no-unsafe-call': 'off',
41
+ '@typescript-eslint/no-unsafe-enum-assignment': 'off',
41
42
  '@typescript-eslint/no-unsafe-enum-comparison': 'off',
42
43
  '@typescript-eslint/no-unsafe-member-access': 'off',
43
44
  '@typescript-eslint/no-unsafe-return': 'off',
@@ -27,6 +27,7 @@ declare const _default: {
27
27
  '@typescript-eslint/no-unsafe-argument': "error";
28
28
  '@typescript-eslint/no-unsafe-assignment': "error";
29
29
  '@typescript-eslint/no-unsafe-call': "error";
30
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
30
31
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
31
32
  '@typescript-eslint/no-unsafe-member-access': "error";
32
33
  '@typescript-eslint/no-unsafe-return': "error";
@@ -34,6 +34,7 @@ module.exports = {
34
34
  '@typescript-eslint/no-unsafe-argument': 'error',
35
35
  '@typescript-eslint/no-unsafe-assignment': 'error',
36
36
  '@typescript-eslint/no-unsafe-call': 'error',
37
+ '@typescript-eslint/no-unsafe-enum-assignment': 'error',
37
38
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
38
39
  '@typescript-eslint/no-unsafe-member-access': 'error',
39
40
  '@typescript-eslint/no-unsafe-return': 'error',
@@ -48,6 +48,7 @@ declare const _default: {
48
48
  '@typescript-eslint/no-unsafe-assignment': "error";
49
49
  '@typescript-eslint/no-unsafe-call': "error";
50
50
  '@typescript-eslint/no-unsafe-declaration-merging': "error";
51
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
51
52
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
52
53
  '@typescript-eslint/no-unsafe-function-type': "error";
53
54
  '@typescript-eslint/no-unsafe-member-access': "error";
@@ -56,6 +56,7 @@ module.exports = {
56
56
  '@typescript-eslint/no-unsafe-assignment': 'error',
57
57
  '@typescript-eslint/no-unsafe-call': 'error',
58
58
  '@typescript-eslint/no-unsafe-declaration-merging': 'error',
59
+ '@typescript-eslint/no-unsafe-enum-assignment': 'error',
59
60
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
60
61
  '@typescript-eslint/no-unsafe-function-type': 'error',
61
62
  '@typescript-eslint/no-unsafe-member-access': 'error',
@@ -112,6 +112,7 @@ exports.default = (plugin, parser) => [
112
112
  '@typescript-eslint/no-unsafe-assignment': 'error',
113
113
  '@typescript-eslint/no-unsafe-call': 'error',
114
114
  '@typescript-eslint/no-unsafe-declaration-merging': 'error',
115
+ '@typescript-eslint/no-unsafe-enum-assignment': 'error',
115
116
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
116
117
  '@typescript-eslint/no-unsafe-function-type': 'error',
117
118
  '@typescript-eslint/no-unsafe-member-access': 'error',
@@ -43,6 +43,7 @@ exports.default = (_plugin, _parser) => ({
43
43
  '@typescript-eslint/no-unsafe-argument': 'off',
44
44
  '@typescript-eslint/no-unsafe-assignment': 'off',
45
45
  '@typescript-eslint/no-unsafe-call': 'off',
46
+ '@typescript-eslint/no-unsafe-enum-assignment': 'off',
46
47
  '@typescript-eslint/no-unsafe-enum-comparison': 'off',
47
48
  '@typescript-eslint/no-unsafe-member-access': 'off',
48
49
  '@typescript-eslint/no-unsafe-return': 'off',
@@ -47,6 +47,7 @@ exports.default = (plugin, parser) => [
47
47
  '@typescript-eslint/no-unsafe-argument': 'error',
48
48
  '@typescript-eslint/no-unsafe-assignment': 'error',
49
49
  '@typescript-eslint/no-unsafe-call': 'error',
50
+ '@typescript-eslint/no-unsafe-enum-assignment': 'error',
50
51
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
51
52
  '@typescript-eslint/no-unsafe-member-access': 'error',
52
53
  '@typescript-eslint/no-unsafe-return': 'error',
@@ -69,6 +69,7 @@ exports.default = (plugin, parser) => [
69
69
  '@typescript-eslint/no-unsafe-assignment': 'error',
70
70
  '@typescript-eslint/no-unsafe-call': 'error',
71
71
  '@typescript-eslint/no-unsafe-declaration-merging': 'error',
72
+ '@typescript-eslint/no-unsafe-enum-assignment': 'error',
72
73
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
73
74
  '@typescript-eslint/no-unsafe-function-type': 'error',
74
75
  '@typescript-eslint/no-unsafe-member-access': 'error',
package/dist/index.d.ts CHANGED
@@ -94,6 +94,7 @@ declare const _default: {
94
94
  '@typescript-eslint/no-unsafe-assignment': "error";
95
95
  '@typescript-eslint/no-unsafe-call': "error";
96
96
  '@typescript-eslint/no-unsafe-declaration-merging': "error";
97
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
97
98
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
98
99
  '@typescript-eslint/no-unsafe-function-type': "error";
99
100
  '@typescript-eslint/no-unsafe-member-access': "error";
@@ -199,6 +200,7 @@ declare const _default: {
199
200
  '@typescript-eslint/no-unsafe-argument': "off";
200
201
  '@typescript-eslint/no-unsafe-assignment': "off";
201
202
  '@typescript-eslint/no-unsafe-call': "off";
203
+ '@typescript-eslint/no-unsafe-enum-assignment': "off";
202
204
  '@typescript-eslint/no-unsafe-enum-comparison': "off";
203
205
  '@typescript-eslint/no-unsafe-member-access': "off";
204
206
  '@typescript-eslint/no-unsafe-return': "off";
@@ -498,6 +500,7 @@ declare const _default: {
498
500
  '@typescript-eslint/no-unsafe-assignment': "error";
499
501
  '@typescript-eslint/no-unsafe-call': "error";
500
502
  '@typescript-eslint/no-unsafe-declaration-merging': "error";
503
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
501
504
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
502
505
  '@typescript-eslint/no-unsafe-function-type': "error";
503
506
  '@typescript-eslint/no-unsafe-member-access': "error";
@@ -575,6 +578,7 @@ declare const _default: {
575
578
  '@typescript-eslint/no-unsafe-argument': "error";
576
579
  '@typescript-eslint/no-unsafe-assignment': "error";
577
580
  '@typescript-eslint/no-unsafe-call': "error";
581
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
578
582
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
579
583
  '@typescript-eslint/no-unsafe-member-access': "error";
580
584
  '@typescript-eslint/no-unsafe-return': "error";
@@ -957,6 +961,9 @@ declare const _default: {
957
961
  'no-unsafe-declaration-merging': import("@typescript-eslint/utils/ts-eslint").RuleModule<"unsafeMerging", [], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
958
962
  name: string;
959
963
  };
964
+ 'no-unsafe-enum-assignment': import("@typescript-eslint/utils/ts-eslint").RuleModule<"unsafeEnumAccess" | "unsafeEnumArgument" | "unsafeEnumAssertion" | "unsafeEnumAssignment" | "unsafeEnumMutation" | "unsafeEnumReturn", [], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
965
+ name: string;
966
+ };
960
967
  'no-unsafe-enum-comparison': import("@typescript-eslint/utils/ts-eslint").RuleModule<"mismatchedCase" | "mismatchedCondition" | "replaceValueWithEnum", [], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
961
968
  name: string;
962
969
  };
@@ -116,6 +116,7 @@ declare const _default: {
116
116
  '@typescript-eslint/no-unsafe-assignment': "error";
117
117
  '@typescript-eslint/no-unsafe-call': "error";
118
118
  '@typescript-eslint/no-unsafe-declaration-merging': "error";
119
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
119
120
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
120
121
  '@typescript-eslint/no-unsafe-function-type': "error";
121
122
  '@typescript-eslint/no-unsafe-member-access': "error";
@@ -221,6 +222,7 @@ declare const _default: {
221
222
  '@typescript-eslint/no-unsafe-argument': "off";
222
223
  '@typescript-eslint/no-unsafe-assignment': "off";
223
224
  '@typescript-eslint/no-unsafe-call': "off";
225
+ '@typescript-eslint/no-unsafe-enum-assignment': "off";
224
226
  '@typescript-eslint/no-unsafe-enum-comparison': "off";
225
227
  '@typescript-eslint/no-unsafe-member-access': "off";
226
228
  '@typescript-eslint/no-unsafe-return': "off";
@@ -521,6 +523,7 @@ declare const _default: {
521
523
  '@typescript-eslint/no-unsafe-assignment': "error";
522
524
  '@typescript-eslint/no-unsafe-call': "error";
523
525
  '@typescript-eslint/no-unsafe-declaration-merging': "error";
526
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
524
527
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
525
528
  '@typescript-eslint/no-unsafe-function-type': "error";
526
529
  '@typescript-eslint/no-unsafe-member-access': "error";
@@ -598,6 +601,7 @@ declare const _default: {
598
601
  '@typescript-eslint/no-unsafe-argument': "error";
599
602
  '@typescript-eslint/no-unsafe-assignment': "error";
600
603
  '@typescript-eslint/no-unsafe-call': "error";
604
+ '@typescript-eslint/no-unsafe-enum-assignment': "error";
601
605
  '@typescript-eslint/no-unsafe-enum-comparison': "error";
602
606
  '@typescript-eslint/no-unsafe-member-access': "error";
603
607
  '@typescript-eslint/no-unsafe-return': "error";
@@ -980,6 +984,9 @@ declare const _default: {
980
984
  'no-unsafe-declaration-merging': TSESLint.RuleModule<"unsafeMerging", [], import("../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
981
985
  name: string;
982
986
  };
987
+ 'no-unsafe-enum-assignment': TSESLint.RuleModule<"unsafeEnumAccess" | "unsafeEnumArgument" | "unsafeEnumAssertion" | "unsafeEnumAssignment" | "unsafeEnumMutation" | "unsafeEnumReturn", [], import("../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
988
+ name: string;
989
+ };
983
990
  'no-unsafe-enum-comparison': TSESLint.RuleModule<"mismatchedCase" | "mismatchedCondition" | "replaceValueWithEnum", [], import("../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
984
991
  name: string;
985
992
  };
@@ -24,6 +24,10 @@ export declare function getEnumTypes(typeChecker: ts.TypeChecker, type: ts.Type)
24
24
  * compared against a non-enum value of the same primitive kind.
25
25
  */
26
26
  export declare function isMismatchedEnumComparisonTypes(typeChecker: ts.TypeChecker, leftType: ts.Type, rightType: ts.Type): boolean;
27
+ /**
28
+ * @returns What type a type's enum value is (number or string), if either.
29
+ */
30
+ export declare function getEnumValueType(type: ts.Type): ts.TypeFlags | undefined;
27
31
  /**
28
32
  * Returns the enum key that matches the given literal node, or null if none
29
33
  * match. For example:
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getEnumLiterals = getEnumLiterals;
37
37
  exports.getEnumTypes = getEnumTypes;
38
38
  exports.isMismatchedEnumComparisonTypes = isMismatchedEnumComparisonTypes;
39
+ exports.getEnumValueType = getEnumValueType;
39
40
  exports.getEnumKeyForLiteral = getEnumKeyForLiteral;
40
41
  const tsutils = __importStar(require("ts-api-utils"));
41
42
  const ts = __importStar(require("typescript"));
@@ -278,6 +278,9 @@ declare const rules: {
278
278
  'no-unsafe-declaration-merging': import("@typescript-eslint/utils/ts-eslint").RuleModule<"unsafeMerging", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
279
279
  name: string;
280
280
  };
281
+ 'no-unsafe-enum-assignment': import("@typescript-eslint/utils/ts-eslint").RuleModule<"unsafeEnumAccess" | "unsafeEnumArgument" | "unsafeEnumAssertion" | "unsafeEnumAssignment" | "unsafeEnumMutation" | "unsafeEnumReturn", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
282
+ name: string;
283
+ };
281
284
  'no-unsafe-enum-comparison': import("@typescript-eslint/utils/ts-eslint").RuleModule<"mismatchedCase" | "mismatchedCondition" | "replaceValueWithEnum", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
282
285
  name: string;
283
286
  };
@@ -84,6 +84,7 @@ const no_unsafe_argument_1 = __importDefault(require("./no-unsafe-argument"));
84
84
  const no_unsafe_assignment_1 = __importDefault(require("./no-unsafe-assignment"));
85
85
  const no_unsafe_call_1 = __importDefault(require("./no-unsafe-call"));
86
86
  const no_unsafe_declaration_merging_1 = __importDefault(require("./no-unsafe-declaration-merging"));
87
+ const no_unsafe_enum_assignment_1 = __importDefault(require("./no-unsafe-enum-assignment"));
87
88
  const no_unsafe_enum_comparison_1 = __importDefault(require("./no-unsafe-enum-comparison"));
88
89
  const no_unsafe_function_type_1 = __importDefault(require("./no-unsafe-function-type"));
89
90
  const no_unsafe_member_access_1 = __importDefault(require("./no-unsafe-member-access"));
@@ -220,6 +221,7 @@ const rules = {
220
221
  'no-unsafe-assignment': no_unsafe_assignment_1.default,
221
222
  'no-unsafe-call': no_unsafe_call_1.default,
222
223
  'no-unsafe-declaration-merging': no_unsafe_declaration_merging_1.default,
224
+ 'no-unsafe-enum-assignment': no_unsafe_enum_assignment_1.default,
223
225
  'no-unsafe-enum-comparison': no_unsafe_enum_comparison_1.default,
224
226
  'no-unsafe-function-type': no_unsafe_function_type_1.default,
225
227
  'no-unsafe-member-access': no_unsafe_member_access_1.default,
@@ -509,8 +509,13 @@ exports.default = (0, util_1.createRule)({
509
509
  while (current && !(0, util_1.isFunction)(current)) {
510
510
  current = current.parent;
511
511
  }
512
- return (0, util_1.nullThrows)(current, util_1.NullThrowsReasons.MissingParent);
512
+ return current;
513
513
  })();
514
+ // A `return` with no enclosing function is legal in a CommonJS module, and
515
+ // there is no function signature for the returned value to be misused against.
516
+ if (!functionNode) {
517
+ return;
518
+ }
514
519
  if (functionNode.returnType &&
515
520
  !isPossiblyFunctionType(functionNode.returnType)) {
516
521
  return;
@@ -308,7 +308,9 @@ exports.default = (0, util_1.createRule)({
308
308
  messageId: 'primitiveOverridden',
309
309
  data: {
310
310
  literal: typeValues.map(name => name.typeName).join(' | '),
311
- primitive: primitiveTypeFlagNames[primitive],
311
+ primitive: primitiveTypeFlagNames[
312
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
313
+ primitive],
312
314
  },
313
315
  });
314
316
  }
@@ -41,6 +41,7 @@ const assertionFunctionUtils_1 = require("../util/assertionFunctionUtils");
41
41
  // #region
42
42
  const nullishFlag = ts.TypeFlags.Undefined | ts.TypeFlags.Null;
43
43
  function isNullishType(type) {
44
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
44
45
  return tsutils.isTypeFlagSet(type, nullishFlag);
45
46
  }
46
47
  function isAlwaysNullish(type) {
@@ -4,7 +4,7 @@ export type Options = [
4
4
  typesToIgnore?: string[];
5
5
  }
6
6
  ];
7
- export type MessageIds = 'contextuallyUnnecessary' | 'unnecessaryAssertion';
7
+ export type MessageIds = 'contextuallyInferredTypeArguments' | 'contextuallyUnnecessary' | 'unnecessaryAssertion';
8
8
  declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
9
9
  name: string;
10
10
  };
@@ -48,6 +48,7 @@ exports.default = (0, util_1.createRule)({
48
48
  },
49
49
  fixable: 'code',
50
50
  messages: {
51
+ contextuallyInferredTypeArguments: 'The type arguments for this generic call may be inferred from the assertion. Specify them explicitly instead.',
51
52
  contextuallyUnnecessary: 'This assertion is unnecessary since the receiver accepts the original type of the expression.',
52
53
  unnecessaryAssertion: 'This assertion is unnecessary since it does not change the type of the expression.',
53
54
  },
@@ -381,6 +382,27 @@ exports.default = (0, util_1.createRule)({
381
382
  function hasGenericCallSignature(type) {
382
383
  return type.getCallSignatures().some(hasTypeParams);
383
384
  }
385
+ function getInnermostCall(expression) {
386
+ switch (expression.type) {
387
+ case utils_1.AST_NODE_TYPES.AwaitExpression:
388
+ return getInnermostCall(expression.argument);
389
+ case utils_1.AST_NODE_TYPES.CallExpression:
390
+ return expression;
391
+ case utils_1.AST_NODE_TYPES.ChainExpression:
392
+ case utils_1.AST_NODE_TYPES.TSNonNullExpression:
393
+ return getInnermostCall(expression.expression);
394
+ case utils_1.AST_NODE_TYPES.SequenceExpression:
395
+ return getInnermostCall((0, util_1.nullThrows)(expression.expressions.at(-1), 'Expected SequenceExpression to have at least one expression'));
396
+ default:
397
+ return undefined;
398
+ }
399
+ }
400
+ function isGenericCallWithInferredTypeArguments(expression) {
401
+ const call = getInnermostCall(expression);
402
+ return (call != null &&
403
+ call.typeArguments == null &&
404
+ hasGenericCallSignature(services.getTypeAtLocation(call.callee)));
405
+ }
384
406
  function isArgumentToOverloadedFunction(node) {
385
407
  const { parent } = node;
386
408
  if ((parent.type !== utils_1.AST_NODE_TYPES.CallExpression &&
@@ -647,11 +669,19 @@ exports.default = (0, util_1.createRule)({
647
669
  ? isImplicitlyNarrowedLiteralDeclaration(node)
648
670
  : !typeAnnotationIsConstAssertion;
649
671
  if (typeIsUnchanged && wouldSameTypeBeInferred) {
650
- context.report({
651
- node,
652
- messageId: 'unnecessaryAssertion',
653
- fix: createAssertionFixer(node),
654
- });
672
+ if (isGenericCallWithInferredTypeArguments(node.expression)) {
673
+ context.report({
674
+ node,
675
+ messageId: 'contextuallyInferredTypeArguments',
676
+ });
677
+ }
678
+ else {
679
+ context.report({
680
+ node,
681
+ messageId: 'unnecessaryAssertion',
682
+ fix: createAssertionFixer(node),
683
+ });
684
+ }
655
685
  return;
656
686
  }
657
687
  const originalNode = services.esTreeNodeToTSNodeMap.get(node);
@@ -62,6 +62,7 @@ exports.default = (0, util_1.createRule)({
62
62
  [utils_1.AST_NODE_TYPES.TSUnknownKeyword, 'unknown'],
63
63
  ]);
64
64
  function checkRequiresGenericDeclarationDisambiguation(filename) {
65
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
65
66
  const pathExt = (0, node_path_1.extname)(filename).toLocaleLowerCase();
66
67
  switch (pathExt) {
67
68
  case ts.Extension.Cts:
@@ -0,0 +1,5 @@
1
+ type MessageIds = 'unsafeEnumAccess' | 'unsafeEnumArgument' | 'unsafeEnumAssertion' | 'unsafeEnumAssignment' | 'unsafeEnumMutation' | 'unsafeEnumReturn';
2
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
3
+ name: string;
4
+ };
5
+ export default _default;
@@ -0,0 +1,473 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const utils_1 = require("@typescript-eslint/utils");
37
+ const tsutils = __importStar(require("ts-api-utils"));
38
+ const ts = __importStar(require("typescript"));
39
+ const util_1 = require("../util");
40
+ const getParentFunctionNode_1 = require("../util/getParentFunctionNode");
41
+ const shared_1 = require("./enum-utils/shared");
42
+ const assigningOperators = new Set([
43
+ '=',
44
+ '&&=',
45
+ '&=',
46
+ '??=',
47
+ '^=',
48
+ '|=',
49
+ '||=',
50
+ ]);
51
+ const bitwiseOperators = new Set(['&', '^', '|']);
52
+ exports.default = (0, util_1.createRule)({
53
+ name: 'no-unsafe-enum-assignment',
54
+ meta: {
55
+ type: 'problem',
56
+ docs: {
57
+ description: 'Disallow assigning non-enum values to enum typed locations',
58
+ recommended: 'strict',
59
+ requiresTypeChecking: true,
60
+ },
61
+ messages: {
62
+ unsafeEnumAccess: 'The computed key used here does not have a shared enum type with the expected enum {{enumNames}}.',
63
+ unsafeEnumArgument: 'The argument passed here does not have a shared enum type with the expected enum {{enumNames}}.',
64
+ unsafeEnumAssertion: 'The value asserted here does not have a shared enum type with the expected enum {{enumNames}}.',
65
+ unsafeEnumAssignment: 'The value assigned here does not have a shared enum type with the expected enum {{enumNames}}.',
66
+ unsafeEnumMutation: 'This mutation can produce a value outside of the expected enum {{enumNames}}.',
67
+ unsafeEnumReturn: 'The value returned here does not have a shared enum type with the expected enum {{enumNames}}.',
68
+ },
69
+ schema: [],
70
+ },
71
+ defaultOptions: [],
72
+ create(context) {
73
+ const services = (0, util_1.getParserServices)(context);
74
+ const checker = services.program.getTypeChecker();
75
+ const checkedNodes = new WeakSet();
76
+ function report(node, messageId, receiverTypes) {
77
+ context.report({
78
+ node,
79
+ messageId,
80
+ data: { enumNames: describeEnumTypes(checker, receiverTypes) },
81
+ });
82
+ }
83
+ // Literals inside an already reported value would otherwise be reported
84
+ // again by their own handlers:
85
+ //
86
+ // ```ts
87
+ // const value: T = [Fruit.Apple, 1] as const;
88
+ // ```
89
+ function markChecked(node) {
90
+ checkedNodes.add(node);
91
+ switch (node.type) {
92
+ case utils_1.AST_NODE_TYPES.ArrayExpression:
93
+ node.elements.forEach(element => {
94
+ if (element) {
95
+ markChecked(element);
96
+ }
97
+ });
98
+ break;
99
+ case utils_1.AST_NODE_TYPES.ConditionalExpression:
100
+ markChecked(node.consequent);
101
+ markChecked(node.alternate);
102
+ break;
103
+ case utils_1.AST_NODE_TYPES.LogicalExpression:
104
+ markChecked(node.left);
105
+ markChecked(node.right);
106
+ break;
107
+ case utils_1.AST_NODE_TYPES.ObjectExpression:
108
+ node.properties.forEach(markChecked);
109
+ break;
110
+ case utils_1.AST_NODE_TYPES.Property:
111
+ markChecked(node.value);
112
+ break;
113
+ case utils_1.AST_NODE_TYPES.SpreadElement:
114
+ markChecked(node.argument);
115
+ break;
116
+ case utils_1.AST_NODE_TYPES.TSAsExpression:
117
+ case utils_1.AST_NODE_TYPES.TSNonNullExpression:
118
+ case utils_1.AST_NODE_TYPES.TSSatisfiesExpression:
119
+ case utils_1.AST_NODE_TYPES.TSTypeAssertion:
120
+ markChecked(node.expression);
121
+ break;
122
+ }
123
+ }
124
+ function getContextualType(node) {
125
+ return checker.getContextualType(services.esTreeNodeToTSNodeMap.get(node));
126
+ }
127
+ // Bitwise combinations of an enum's own members are its bit flags:
128
+ //
129
+ // ```ts
130
+ // const readWrite: Flags = Flags.Read | Flags.Write;
131
+ // flags &= ~Flags.Write;
132
+ // ```
133
+ function isSafeEnumBitwiseExpression(node, receiverType) {
134
+ function isSafeOperand(operand) {
135
+ return (isSafeEnumBitwiseExpression(operand, receiverType) ||
136
+ !isMismatchedEnumAssignmentTypes(checker, services.getTypeAtLocation(operand), receiverType));
137
+ }
138
+ switch (node.type) {
139
+ case utils_1.AST_NODE_TYPES.BinaryExpression:
140
+ return (bitwiseOperators.has(node.operator) &&
141
+ isSafeOperand(node.left) &&
142
+ isSafeOperand(node.right));
143
+ case utils_1.AST_NODE_TYPES.UnaryExpression:
144
+ return node.operator === '~' && isSafeOperand(node.argument);
145
+ default:
146
+ return false;
147
+ }
148
+ }
149
+ function isUnsafeAssignment(senderNode, receiverType, senderType = services.getTypeAtLocation(senderNode)) {
150
+ return (hasDeepEnumAssignmentMismatch(checker, senderType, receiverType) &&
151
+ !isSafeEnumBitwiseExpression(senderNode, receiverType));
152
+ }
153
+ function checkAssignment(receiverType, senderNode, reportingNode, messageId = 'unsafeEnumAssignment', senderType) {
154
+ // Object and array literals are reported per property and element by
155
+ // their own handlers instead:
156
+ //
157
+ // ```ts
158
+ // const box: { fruit: Fruit } = { fruit: 1 };
159
+ // ```
160
+ if (senderNode.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
161
+ senderNode.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
162
+ !isUnsafeAssignment(senderNode, receiverType, senderType)) {
163
+ return;
164
+ }
165
+ report(reportingNode, messageId, [receiverType]);
166
+ markChecked(senderNode);
167
+ }
168
+ function checkArguments(node, args) {
169
+ const signature = util_1.FunctionSignature.create(checker, services.esTreeNodeToTSNodeMap.get(node));
170
+ if (node.type === utils_1.AST_NODE_TYPES.TaggedTemplateExpression) {
171
+ // The first parameter receives the template's strings, not a value.
172
+ signature.getNextParameterType();
173
+ }
174
+ for (const argument of args) {
175
+ if (argument.type === utils_1.AST_NODE_TYPES.SpreadElement) {
176
+ const spreadType = services.getTypeAtLocation(argument.argument);
177
+ // takesFruits(...[Fruit.Apple, 1]);
178
+ if (checker.isTupleType(spreadType)) {
179
+ const mismatchedParameterTypes = checker
180
+ .getTypeArguments(spreadType)
181
+ .flatMap(elementType => {
182
+ const parameterType = signature.getNextParameterType();
183
+ return parameterType != null &&
184
+ hasDeepEnumAssignmentMismatch(checker, elementType, parameterType)
185
+ ? [parameterType]
186
+ : [];
187
+ });
188
+ if (mismatchedParameterTypes.length > 0) {
189
+ report(argument, 'unsafeEnumArgument', mismatchedParameterTypes);
190
+ }
191
+ if (spreadType.target.combinedFlags & ts.ElementFlags.Variable) {
192
+ signature.consumeRemainingArguments();
193
+ }
194
+ continue;
195
+ }
196
+ }
197
+ // takesFruit(1);
198
+ // takesFruits(...numbers);
199
+ const parameterType = signature.getNextParameterType();
200
+ if (parameterType != null) {
201
+ checkAssignment(parameterType, argument, argument, 'unsafeEnumArgument');
202
+ }
203
+ }
204
+ }
205
+ function checkClassMember(node) {
206
+ // Class members don't get contextually typed by the members they
207
+ // implement or override, so those types are also checked explicitly:
208
+ //
209
+ // ```ts
210
+ // class Basket implements HasFruit {
211
+ // fruit = 1;
212
+ // }
213
+ // ```
214
+ const heritageMemberTypes = getHeritageMemberTypes(node);
215
+ if (heritageMemberTypes.length > 0 &&
216
+ heritageMemberTypes.every(heritageMemberType => isUnsafeAssignment(node.value, heritageMemberType))) {
217
+ report(node, 'unsafeEnumAssignment', heritageMemberTypes);
218
+ markChecked(node.value);
219
+ return;
220
+ }
221
+ checkAssignment(services.getTypeAtLocation(node), node.value, node);
222
+ }
223
+ function getHeritageMemberTypes(node) {
224
+ const memberName = (0, util_1.getStaticMemberAccessValue)(node, context);
225
+ if (typeof memberName !== 'string') {
226
+ return [];
227
+ }
228
+ const classNode = services.esTreeNodeToTSNodeMap.get(node).parent;
229
+ return (classNode.heritageClauses ?? []).flatMap(heritageClause => heritageClause.types.flatMap(heritageType => {
230
+ const memberSymbol = checker
231
+ .getTypeAtLocation(heritageType)
232
+ .getProperty(memberName);
233
+ return memberSymbol ? [checker.getTypeOfSymbol(memberSymbol)] : [];
234
+ }));
235
+ }
236
+ function checkMutation(targetNode, reportingNode) {
237
+ const targetType = services.getTypeAtLocation(targetNode);
238
+ if ((0, shared_1.getEnumTypes)(checker, getConstraintType(checker, targetType)).length > 0) {
239
+ report(reportingNode, 'unsafeEnumMutation', [targetType]);
240
+ }
241
+ }
242
+ function checkReturn(returnNode, reportingNode) {
243
+ const functionNode = (0, getParentFunctionNode_1.getParentFunctionNode)(returnNode);
244
+ if (functionNode == null) {
245
+ // return 1;
246
+ return;
247
+ }
248
+ const signature = (0, util_1.nullThrows)(checker.getSignatureFromDeclaration(services.esTreeNodeToTSNodeMap.get(functionNode)), 'Expected the function to have a signature.');
249
+ let receiverType = signature.getReturnType();
250
+ let senderType = services.getTypeAtLocation(returnNode);
251
+ // async function getFruit(): Promise<Fruit> {
252
+ // return Promise.resolve(1);
253
+ // }
254
+ if (functionNode.async) {
255
+ receiverType = checker.getAwaitedType(receiverType);
256
+ senderType = checker.getAwaitedType(senderType);
257
+ }
258
+ if (receiverType && senderType) {
259
+ checkAssignment(receiverType, returnNode, reportingNode, 'unsafeEnumReturn', senderType);
260
+ }
261
+ }
262
+ function checkTypeAssertion(node) {
263
+ checkAssignment(services.getTypeAtLocation(node.typeAnnotation), node.expression, node, 'unsafeEnumAssertion');
264
+ }
265
+ return {
266
+ 'AccessorProperty[value != null], PropertyDefinition[value != null]': checkClassMember,
267
+ ArrayExpression(node) {
268
+ if (checkedNodes.has(node)) {
269
+ return;
270
+ }
271
+ // const fruits: Fruit[] = [1, ...numbers];
272
+ for (const element of node.elements) {
273
+ if (element) {
274
+ const receiverType = getContextualType(element);
275
+ if (receiverType) {
276
+ checkAssignment(receiverType, element, element);
277
+ }
278
+ }
279
+ }
280
+ },
281
+ 'ArrowFunctionExpression[body.type != "BlockStatement"]'(node) {
282
+ checkReturn(node.body, node.body);
283
+ },
284
+ AssignmentExpression(node) {
285
+ if (assigningOperators.has(node.operator)) {
286
+ checkAssignment(services.getTypeAtLocation(node.left), node.right, node);
287
+ }
288
+ else {
289
+ checkMutation(node.left, node);
290
+ }
291
+ },
292
+ AssignmentPattern(node) {
293
+ checkAssignment(services.getTypeAtLocation(node.left), node.right, node);
294
+ },
295
+ 'CallExpression, NewExpression'(node) {
296
+ checkArguments(node, node.arguments);
297
+ },
298
+ 'JSXAttribute > JSXExpressionContainer > :not(JSXEmptyExpression)'(node) {
299
+ const receiverType = getContextualType(node);
300
+ if (receiverType) {
301
+ checkAssignment(receiverType, node, node);
302
+ }
303
+ },
304
+ 'MemberExpression[computed = true]'(node) {
305
+ const receiverTypes = checker
306
+ .getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(node).expression)
307
+ ?.declarations?.flatMap(declaration => getMappedKeyConstraintTypes(checker, declaration)) ?? [];
308
+ if (receiverTypes.length === 0) {
309
+ return;
310
+ }
311
+ // declare const foo: { [key in Fruit]: string };
312
+ // foo[0];
313
+ const senderType = services.getTypeAtLocation(node.property);
314
+ if (receiverTypes.every(receiverType => hasDeepEnumAssignmentMismatch(checker, senderType, receiverType) || !checker.isTypeAssignableTo(senderType, receiverType))) {
315
+ report(node.property, 'unsafeEnumAccess', receiverTypes);
316
+ }
317
+ },
318
+ ObjectExpression(node) {
319
+ if (checkedNodes.has(node)) {
320
+ return;
321
+ }
322
+ // const box: { fruit: Fruit } = { fruit: 1, ...source };
323
+ for (const property of node.properties) {
324
+ const [receiverNode, senderNode] = property.type === utils_1.AST_NODE_TYPES.SpreadElement
325
+ ? [node, property.argument]
326
+ : [property.value, property.value];
327
+ const receiverType = getContextualType(receiverNode);
328
+ if (receiverType) {
329
+ checkAssignment(receiverType, senderNode, property);
330
+ }
331
+ }
332
+ },
333
+ ReturnStatement(node) {
334
+ if (node.argument) {
335
+ checkReturn(node.argument, node);
336
+ }
337
+ },
338
+ TaggedTemplateExpression(node) {
339
+ checkArguments(node, node.quasi.expressions);
340
+ },
341
+ TSAsExpression: checkTypeAssertion,
342
+ TSTypeAssertion: checkTypeAssertion,
343
+ UpdateExpression(node) {
344
+ checkMutation(node.argument, node);
345
+ },
346
+ 'VariableDeclarator[init != null]'(node) {
347
+ checkAssignment(services.getTypeAtLocation(node.id), node.init, node);
348
+ },
349
+ };
350
+ },
351
+ });
352
+ function getConstraintType(checker, type) {
353
+ return checker.getBaseConstraintOfType(type) ?? type;
354
+ }
355
+ function getTypeArguments(checker, type) {
356
+ return tsutils.isTypeReference(type) ? checker.getTypeArguments(type) : [];
357
+ }
358
+ function hasDeepEnumAssignmentMismatch(checker, senderType, receiverType, visited = new WeakMap()) {
359
+ const constrainedSenderType = getConstraintType(checker, senderType);
360
+ const constrainedReceiverType = getConstraintType(checker, receiverType);
361
+ // Recursive types would otherwise be visited endlessly.
362
+ let visitedReceiverTypes = visited.get(constrainedSenderType);
363
+ if (visitedReceiverTypes == null) {
364
+ visitedReceiverTypes = new WeakSet();
365
+ visited.set(constrainedSenderType, visitedReceiverTypes);
366
+ }
367
+ else if (visitedReceiverTypes.has(constrainedReceiverType)) {
368
+ return false;
369
+ }
370
+ visitedReceiverTypes.add(constrainedReceiverType);
371
+ if (isMismatchedEnumAssignmentTypes(checker, constrainedSenderType, constrainedReceiverType)) {
372
+ return true;
373
+ }
374
+ // Set<number> -> Set<Fruit>
375
+ const senderTypeArguments = getTypeArguments(checker, constrainedSenderType);
376
+ const receiverTypeArguments = getTypeArguments(checker, constrainedReceiverType);
377
+ if (senderTypeArguments.length === receiverTypeArguments.length &&
378
+ senderTypeArguments.some((senderTypeArgument, index) => hasDeepEnumAssignmentMismatch(checker, senderTypeArgument, receiverTypeArguments[index], visited))) {
379
+ return true;
380
+ }
381
+ // [number, Fruit] -> Fruit[]
382
+ const senderElementType = constrainedSenderType.getNumberIndexType();
383
+ const receiverElementType = constrainedReceiverType.getNumberIndexType();
384
+ if (senderElementType &&
385
+ receiverElementType &&
386
+ hasDeepEnumAssignmentMismatch(checker, senderElementType, receiverElementType, visited)) {
387
+ return true;
388
+ }
389
+ // { fruit: number } -> { fruit: Fruit }
390
+ return constrainedReceiverType.getProperties().some(receiverProperty => {
391
+ const senderProperty = constrainedSenderType.getProperty(receiverProperty.name);
392
+ return (senderProperty != null &&
393
+ hasDeepEnumAssignmentMismatch(checker, checker.getTypeOfSymbol(senderProperty), checker.getTypeOfSymbol(receiverProperty), visited));
394
+ });
395
+ }
396
+ function getMappedKeyConstraintTypes(checker, declaration) {
397
+ if (!(ts.isGetAccessorDeclaration(declaration) ||
398
+ ts.isParameter(declaration) ||
399
+ ts.isPropertyDeclaration(declaration) ||
400
+ ts.isPropertySignature(declaration) ||
401
+ ts.isVariableDeclaration(declaration)) ||
402
+ declaration.type == null) {
403
+ return [];
404
+ }
405
+ const typeNode = declaration.type;
406
+ // { [key in Fruit]: string } -> [Fruit]
407
+ if (ts.isMappedTypeNode(typeNode)) {
408
+ return [
409
+ checker.getTypeFromTypeNode((0, util_1.nullThrows)(typeNode.typeParameter.constraint, 'Expected the mapped type parameter to have a constraint.')),
410
+ ];
411
+ }
412
+ // { [Fruit.Apple]: string; [Vegetable.Asparagus]: string } -> [Fruit.Apple, Vegetable.Asparagus]
413
+ if (ts.isTypeLiteralNode(typeNode)) {
414
+ return typeNode.members.flatMap(member => {
415
+ const name = ts.getNameOfDeclaration(member);
416
+ return name && ts.isComputedPropertyName(name)
417
+ ? [checker.getTypeAtLocation(name.expression)]
418
+ : [];
419
+ });
420
+ }
421
+ return [];
422
+ }
423
+ // [Fruit, Set<Vegetable>] -> 'Fruit', 'Vegetable'
424
+ function describeEnumTypes(checker, types) {
425
+ const enumNames = new Set();
426
+ const visited = new Set();
427
+ function visit(type) {
428
+ const constrainedType = getConstraintType(checker, type);
429
+ if (visited.has(constrainedType)) {
430
+ return;
431
+ }
432
+ visited.add(constrainedType);
433
+ for (const enumType of (0, shared_1.getEnumTypes)(checker, constrainedType)) {
434
+ enumNames.add(checker.typeToString(enumType));
435
+ }
436
+ for (const typeArgument of getTypeArguments(checker, constrainedType)) {
437
+ visit(typeArgument);
438
+ }
439
+ const elementType = constrainedType.getNumberIndexType();
440
+ if (elementType) {
441
+ visit(elementType);
442
+ }
443
+ for (const property of constrainedType.getProperties()) {
444
+ visit(checker.getTypeOfSymbol(property));
445
+ }
446
+ }
447
+ types.forEach(visit);
448
+ return [...enumNames]
449
+ .sort()
450
+ .map(enumName => `'${enumName}'`)
451
+ .join(', ');
452
+ }
453
+ function isMismatchedEnumAssignmentTypes(checker, senderType, receiverType) {
454
+ const receiverEnumTypes = (0, shared_1.getEnumTypes)(checker, receiverType);
455
+ const receiverTypeParts = tsutils.unionConstituents(receiverType);
456
+ const receiverEnumValueTypes = new Set(receiverTypeParts.map(shared_1.getEnumValueType));
457
+ const receiverNonEnumParts = receiverTypeParts.filter(receiverTypePart => (0, shared_1.getEnumTypes)(checker, receiverTypePart).length === 0);
458
+ return tsutils.unionConstituents(senderType).some(senderTypePart =>
459
+ // const fruit: Fruit = 1;
460
+ ((receiverEnumValueTypes.has(ts.TypeFlags.Number) &&
461
+ (0, util_1.isNumberLike)(senderTypePart)) ||
462
+ (receiverEnumValueTypes.has(ts.TypeFlags.String) &&
463
+ (0, util_1.isStringLike)(senderTypePart))) &&
464
+ // const fruit: Fruit = Fruit.Apple;
465
+ !hasSharedEnumType(checker, senderTypePart, receiverEnumTypes) &&
466
+ // const fruitOrNumber: Fruit | number = 1;
467
+ !receiverNonEnumParts.some(receiverTypePart => checker.isTypeAssignableTo(senderTypePart, receiverTypePart)));
468
+ }
469
+ function hasSharedEnumType(checker, type, expectedEnumTypes) {
470
+ const typeEnumTypes = new Set((0, shared_1.getEnumTypes)(checker, type));
471
+ return expectedEnumTypes.some(expectedEnumType => typeEnumTypes.has(expectedEnumType));
472
+ }
473
+ //# sourceMappingURL=no-unsafe-enum-assignment.js.map
@@ -195,10 +195,9 @@ exports.default = (0, util_1.createRule)({
195
195
  if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) {
196
196
  return false;
197
197
  }
198
- if (tsutils
199
- .typeConstituents(type)
200
- .some(t => tsutils
198
+ if (tsutils.typeConstituents(type).some(t => tsutils
201
199
  .intersectionConstituents(t)
200
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
202
201
  .some(t => tsutils.isTypeFlagSet(t, ignorableFlags)))) {
203
202
  return false;
204
203
  }
@@ -45,6 +45,7 @@ function includesType(parserServices, node, typeFlagIn) {
45
45
  const typeFlag = typeFlagIn | ts.TypeFlags.Any | ts.TypeFlags.Unknown;
46
46
  const types = (0, ts_api_utils_1.unionConstituents)(parserServices.getTypeAtLocation(node));
47
47
  for (const type of types) {
48
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
48
49
  if ((0, util_1.isTypeFlagSet)(type, typeFlag)) {
49
50
  return true;
50
51
  }
@@ -57,11 +58,15 @@ function isValidAndLastChainOperand(ComparisonValueType, comparisonType, parserS
57
58
  const types = (0, ts_api_utils_1.unionConstituents)(type);
58
59
  switch (comparisonType) {
59
60
  case gatherLogicalOperands_1.ComparisonType.Equal: {
60
- const isNullish = types.some(t => (0, util_1.isTypeFlagSet)(t, ANY_UNKNOWN_FLAGS | ts.TypeFlags.Null | ts.TypeFlags.Undefined));
61
+ const isNullish = types.some(t => (0, util_1.isTypeFlagSet)(t,
62
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
63
+ ANY_UNKNOWN_FLAGS | ts.TypeFlags.Null | ts.TypeFlags.Undefined));
61
64
  return !isNullish;
62
65
  }
63
66
  case gatherLogicalOperands_1.ComparisonType.StrictEqual: {
64
- const isUndefined = types.some(t => (0, util_1.isTypeFlagSet)(t, ANY_UNKNOWN_FLAGS | ts.TypeFlags.Undefined));
67
+ const isUndefined = types.some(t =>
68
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
69
+ (0, util_1.isTypeFlagSet)(t, ANY_UNKNOWN_FLAGS | ts.TypeFlags.Undefined));
65
70
  return !isUndefined;
66
71
  }
67
72
  case gatherLogicalOperands_1.ComparisonType.NotStrictEqual: {
@@ -78,11 +83,15 @@ function isValidOrLastChainOperand(ComparisonValueType, comparisonType, parserSe
78
83
  const types = (0, ts_api_utils_1.unionConstituents)(type);
79
84
  switch (comparisonType) {
80
85
  case gatherLogicalOperands_1.ComparisonType.NotEqual: {
81
- const isNullish = types.some(t => (0, util_1.isTypeFlagSet)(t, ANY_UNKNOWN_FLAGS | ts.TypeFlags.Null | ts.TypeFlags.Undefined));
86
+ const isNullish = types.some(t => (0, util_1.isTypeFlagSet)(t,
87
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
88
+ ANY_UNKNOWN_FLAGS | ts.TypeFlags.Null | ts.TypeFlags.Undefined));
82
89
  return !isNullish;
83
90
  }
84
91
  case gatherLogicalOperands_1.ComparisonType.NotStrictEqual: {
85
- const isUndefined = types.some(t => (0, util_1.isTypeFlagSet)(t, ANY_UNKNOWN_FLAGS | ts.TypeFlags.Undefined));
92
+ const isUndefined = types.some(t =>
93
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
94
+ (0, util_1.isTypeFlagSet)(t, ANY_UNKNOWN_FLAGS | ts.TypeFlags.Undefined));
86
95
  return !isUndefined;
87
96
  }
88
97
  case gatherLogicalOperands_1.ComparisonType.Equal:
@@ -124,6 +124,7 @@ function isValidFalseBooleanCheckType(node, disallowFalseyLiteral, parserService
124
124
  if (options.checkBigInt === true) {
125
125
  allowedFlags |= ts.TypeFlags.BigIntLike;
126
126
  }
127
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
127
128
  return primitiveAndObjectParts.every(t => (0, util_1.isTypeFlagSet)(t, allowedFlags));
128
129
  }
129
130
  function gatherLogicalOperands(node, parserServices, sourceCode, options) {
@@ -303,6 +303,7 @@ exports.default = util.createRule({
303
303
  .getCallSignaturesOfType(actualType)
304
304
  .map(signature => signature.getReturnType())
305
305
  .flatMap(returnType => tsutils.unionConstituents(returnType))
306
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
306
307
  .every(type => tsutils.isTypeFlagSet(type, allowedReturnType))) {
307
308
  // The function is already void.
308
309
  return;
@@ -396,6 +397,7 @@ exports.default = util.createRule({
396
397
  continue;
397
398
  }
398
399
  const returnType = checker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(statement.argument));
400
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
399
401
  if (tsutils.isTypeFlagSet(returnType, allowedReturnType)) {
400
402
  // Only visit return statements with invalid type.
401
403
  continue;
@@ -140,7 +140,7 @@ exports.default = (0, util_1.createRule)({
140
140
  return {
141
141
  containsNonLiteralType,
142
142
  defaultCase: defaultCase ?? getCommentDefaultCase(node),
143
- missingLiteralBranchTypes,
143
+ missingLiteralBranchTypes: missingLiteralBranchTypes.sort((a, b) => typeToString(a).localeCompare(typeToString(b))),
144
144
  symbolName,
145
145
  };
146
146
  }
@@ -310,19 +310,13 @@ function checkIfMethod(symbol, ignoreStatic) {
310
310
  return { dangerous: false };
311
311
  }
312
312
  switch (valueDeclaration.kind) {
313
- case ts.SyntaxKind.PropertyDeclaration:
314
- return {
315
- dangerous: valueDeclaration.initializer?.kind ===
316
- ts.SyntaxKind.FunctionExpression,
317
- };
318
- case ts.SyntaxKind.PropertyAssignment: {
319
- const assignee = valueDeclaration.initializer;
320
- if (assignee.kind !== ts.SyntaxKind.FunctionExpression) {
321
- return {
322
- dangerous: false,
323
- };
313
+ case ts.SyntaxKind.PropertyAssignment:
314
+ case ts.SyntaxKind.PropertyDeclaration: {
315
+ const { initializer } = valueDeclaration;
316
+ if (!initializer || !ts.isFunctionExpression(initializer)) {
317
+ return { dangerous: false };
324
318
  }
325
- return checkMethod(assignee, ignoreStatic);
319
+ return checkMethod(initializer, ignoreStatic);
326
320
  }
327
321
  case ts.SyntaxKind.MethodDeclaration:
328
322
  case ts.SyntaxKind.MethodSignature: {
@@ -417,6 +417,7 @@ function getBinaryOperatorPrecedence(kind) {
417
417
  }
418
418
  // -1 is lower than all other precedences. Returning it will cause binary expression
419
419
  // parsing to stop.
420
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-assignment
420
421
  return -1;
421
422
  }
422
423
  //# sourceMappingURL=getOperatorPrecedence.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/typescript-eslint__eslint-plugin",
3
- "version": "8.70.1-depup.0",
3
+ "version": "8.71.0-depup.0",
4
4
  "description": "TypeScript plugin for ESLint (with updated dependencies)",
5
5
  "files": [
6
6
  "dist",
@@ -55,11 +55,11 @@
55
55
  ],
56
56
  "dependencies": {
57
57
  "@eslint-community/regexpp": "^4.12.2",
58
- "@typescript-eslint/scope-manager": "8.70.1",
59
- "@typescript-eslint/type-utils": "8.70.1",
60
- "@typescript-eslint/utils": "8.70.1",
61
- "@typescript-eslint/visitor-keys": "8.70.1",
62
- "ignore": "^7.0.9",
58
+ "@typescript-eslint/scope-manager": "8.71.0",
59
+ "@typescript-eslint/type-utils": "8.71.0",
60
+ "@typescript-eslint/utils": "8.71.0",
61
+ "@typescript-eslint/visitor-keys": "8.71.0",
62
+ "ignore": "^7.0.10",
63
63
  "natural-compare": "^1.4.0",
64
64
  "ts-api-utils": "^2.5.0"
65
65
  },
@@ -68,8 +68,8 @@
68
68
  "@types/mdast": "^4.0.4",
69
69
  "@types/natural-compare": "^1.4.3",
70
70
  "@types/react": "^18.3.21",
71
- "@typescript-eslint/rule-schema-to-typescript-types": "8.70.1",
72
- "@typescript-eslint/rule-tester": "8.70.1",
71
+ "@typescript-eslint/rule-schema-to-typescript-types": "8.71.0",
72
+ "@typescript-eslint/rule-tester": "8.71.0",
73
73
  "@typescript/native": "npm:typescript@^7.0.2",
74
74
  "@vitest/coverage-v8": "^4.0.18",
75
75
  "ajv": "^6.12.6",
@@ -89,7 +89,7 @@
89
89
  "vitest": "^4.0.18"
90
90
  },
91
91
  "peerDependencies": {
92
- "@typescript-eslint/parser": "^8.70.1",
92
+ "@typescript-eslint/parser": "^8.71.0",
93
93
  "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
94
94
  "typescript": ">=4.8.4 <6.1.0"
95
95
  },
@@ -144,13 +144,13 @@
144
144
  "changes": {
145
145
  "ignore": {
146
146
  "from": "^7.0.5",
147
- "to": "^7.0.9"
147
+ "to": "^7.0.10"
148
148
  }
149
149
  },
150
150
  "depsUpdated": 1,
151
151
  "originalPackage": "@typescript-eslint/eslint-plugin",
152
- "originalVersion": "8.70.1",
153
- "processedAt": "2026-09-22T00:32:50.942Z",
152
+ "originalVersion": "8.71.0",
153
+ "processedAt": "2026-09-29T00:34:20.528Z",
154
154
  "smokeTest": "passed"
155
155
  }
156
156
  }