@typescript-eslint/eslint-plugin 8.53.2-alpha.1 → 8.53.2-alpha.10

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.
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const utils_1 = require("@typescript-eslint/utils");
37
+ const tsutils = __importStar(require("ts-api-utils"));
37
38
  const ts = __importStar(require("typescript"));
38
39
  const util_1 = require("../util");
39
40
  exports.default = (0, util_1.createRule)({
@@ -86,10 +87,10 @@ exports.default = (0, util_1.createRule)({
86
87
  if (symbol.getDeclarations()?.some(ts.isTypeOnlyImportOrExportDeclaration)) {
87
88
  return true;
88
89
  }
89
- if (symbol.flags & ts.SymbolFlags.Value) {
90
+ if (tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Value)) {
90
91
  return false;
91
92
  }
92
- return symbol.flags & ts.SymbolFlags.Alias
93
+ return tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)
93
94
  ? isSymbolTypeBased(checker.getImmediateAliasedSymbol(symbol))
94
95
  : true;
95
96
  }
@@ -127,7 +127,7 @@ exports.default = (0, util_1.createRule)({
127
127
  .getTypeAtLocation(node.object)
128
128
  .getNonNullableType();
129
129
  const indexInfos = checker.getIndexInfosOfType(objectType);
130
- if (indexInfos.some(info => info.keyType.flags & ts.TypeFlags.StringLike)) {
130
+ if (indexInfos.some(info => tsutils.isTypeFlagSet(info.keyType, ts.TypeFlags.StringLike))) {
131
131
  return;
132
132
  }
133
133
  }
@@ -186,8 +186,8 @@ exports.default = (0, util_1.createRule)({
186
186
  return option.checkUnknown ? Usefulness.Sometimes : Usefulness.Always;
187
187
  }
188
188
  // the Boolean type definition missing toString()
189
- if (type.flags & ts.TypeFlags.Boolean ||
190
- type.flags & ts.TypeFlags.BooleanLiteral) {
189
+ if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Boolean) ||
190
+ tsutils.isTypeFlagSet(type, ts.TypeFlags.BooleanLiteral)) {
191
191
  return Usefulness.Always;
192
192
  }
193
193
  const symbol = type.aliasSymbol ?? type.getSymbol();
@@ -97,7 +97,6 @@ exports.default = (0, util_1.createRule)({
97
97
  ],
98
98
  create(context, [options]) {
99
99
  const services = (0, util_1.getParserServices)(context);
100
- const checker = services.program.getTypeChecker();
101
100
  return {
102
101
  'AwaitExpression, CallExpression, TaggedTemplateExpression'(node) {
103
102
  const type = (0, util_1.getConstrainedTypeAtLocation)(services, node);
@@ -338,15 +337,14 @@ exports.default = (0, util_1.createRule)({
338
337
  // - Otherwise, check if the function is a function-expression or an arrow-function.
339
338
  // - If it is, get its contextual type and bail if we cannot.
340
339
  // - Return based on whether the contextual type includes `void` or not
341
- const functionTSNode = services.esTreeNodeToTSNodeMap.get(functionNode);
342
- if (functionTSNode.type) {
343
- const returnType = checker.getTypeFromTypeNode(functionTSNode.type);
340
+ if (functionNode.returnType) {
341
+ const returnType = services.getTypeFromTypeNode(functionNode.returnType.typeAnnotation);
344
342
  return tsutils
345
343
  .unionConstituents(returnType)
346
344
  .some(tsutils.isIntrinsicVoidType);
347
345
  }
348
- if (ts.isExpression(functionTSNode)) {
349
- const functionType = checker.getContextualType(functionTSNode);
346
+ if (functionNode.type !== utils_1.AST_NODE_TYPES.FunctionDeclaration) {
347
+ const functionType = services.getContextualType(functionNode);
350
348
  if (functionType) {
351
349
  return tsutils
352
350
  .unionConstituents(functionType)
@@ -267,8 +267,7 @@ exports.default = (0, util_1.createRule)({
267
267
  false) ?? getJsDocDeprecation(signature));
268
268
  }
269
269
  function getJSXAttributeDeprecation(openingElement, propertyName) {
270
- const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name);
271
- const contextualType = (0, util_1.nullThrows)(checker.getContextualType(tsNode), 'Expected JSX opening element name to have contextualType');
270
+ const contextualType = (0, util_1.nullThrows)(services.getContextualType(openingElement.name), 'Expected JSX opening element name to have contextualType');
272
271
  const symbol = contextualType.getProperty(propertyName);
273
272
  return getJsDocDeprecation(symbol);
274
273
  }
@@ -79,7 +79,7 @@ exports.default = (0, util_1.createRule)({
79
79
  };
80
80
  const argType = services.getTypeAtLocation(node.argument);
81
81
  const unionParts = tsutils.unionConstituents(argType);
82
- if (unionParts.every(part => part.flags & (ts.TypeFlags.Void | ts.TypeFlags.Undefined))) {
82
+ if (unionParts.every(part => tsutils.isTypeFlagSet(part, ts.TypeFlags.Void | ts.TypeFlags.Undefined))) {
83
83
  context.report({
84
84
  node,
85
85
  messageId: 'meaninglessVoidOperator',
@@ -88,8 +88,7 @@ exports.default = (0, util_1.createRule)({
88
88
  });
89
89
  }
90
90
  else if (checkNever &&
91
- unionParts.every(part => part.flags &
92
- (ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never))) {
91
+ unionParts.every(part => tsutils.isTypeFlagSet(part, ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never))) {
93
92
  context.report({
94
93
  node,
95
94
  messageId: 'meaninglessVoidOperator',
@@ -281,8 +281,17 @@ exports.default = (0, util_1.createRule)({
281
281
  return;
282
282
  }
283
283
  const originalNode = services.esTreeNodeToTSNodeMap.get(node);
284
- const type = (0, util_1.getConstrainedTypeAtLocation)(services, node.expression);
285
- if (!(0, util_1.isNullableType)(type)) {
284
+ const constrainedType = (0, util_1.getConstrainedTypeAtLocation)(services, node.expression);
285
+ const actualType = services.getTypeAtLocation(node.expression);
286
+ // Check both the constrained type and the actual type.
287
+ // If either is nullable, we should not report the assertion as unnecessary.
288
+ // This handles cases like generic constraints with `any` where the
289
+ // constrained type is `any` (nullable) but the actual type might be
290
+ // a type parameter that TypeScript treats nominally.
291
+ // See: https://github.com/typescript-eslint/typescript-eslint/issues/11559
292
+ const constrainedTypeIsNullable = (0, util_1.isNullableType)(constrainedType);
293
+ const actualTypeIsNullable = (0, util_1.isNullableType)(actualType);
294
+ if (!constrainedTypeIsNullable && !actualTypeIsNullable) {
286
295
  if (node.expression.type === utils_1.AST_NODE_TYPES.Identifier &&
287
296
  isPossiblyUsedBeforeAssigned(node.expression)) {
288
297
  return;
@@ -296,17 +305,25 @@ exports.default = (0, util_1.createRule)({
296
305
  else {
297
306
  // we know it's a nullable type
298
307
  // so figure out if the variable is used in a place that accepts nullable types
308
+ // If the constrained type differs from the actual type (e.g., when dealing
309
+ // with unresolved generic type parameters), we should not report the assertion
310
+ // as contextually unnecessary. TypeScript may still require the assertion
311
+ // even if the constraint is nullable (like `any`).
312
+ // See: https://github.com/typescript-eslint/typescript-eslint/issues/11559
313
+ if (constrainedType !== actualType) {
314
+ return;
315
+ }
299
316
  const contextualType = (0, util_1.getContextualType)(checker, originalNode);
300
317
  if (contextualType) {
301
- if ((0, util_1.isTypeFlagSet)(type, ts.TypeFlags.Unknown) &&
318
+ if ((0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Unknown) &&
302
319
  !(0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Unknown)) {
303
320
  return;
304
321
  }
305
322
  // in strict mode you can't assign null to undefined, so we have to make sure that
306
323
  // the two types share a nullable type
307
- const typeIncludesUndefined = (0, util_1.isTypeFlagSet)(type, ts.TypeFlags.Undefined);
308
- const typeIncludesNull = (0, util_1.isTypeFlagSet)(type, ts.TypeFlags.Null);
309
- const typeIncludesVoid = (0, util_1.isTypeFlagSet)(type, ts.TypeFlags.Void);
324
+ const typeIncludesUndefined = (0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Undefined);
325
+ const typeIncludesNull = (0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Null);
326
+ const typeIncludesVoid = (0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Void);
310
327
  const contextualTypeIncludesUndefined = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Undefined);
311
328
  const contextualTypeIncludesNull = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Null);
312
329
  const contextualTypeIncludesVoid = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Void);
@@ -45,7 +45,7 @@ function isEnumMemberType(type) {
45
45
  if (!symbol) {
46
46
  return false;
47
47
  }
48
- return (symbol.flags & ts.SymbolFlags.EnumMember) !== 0;
48
+ return tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.EnumMember);
49
49
  }
50
50
  exports.default = (0, util_1.createRule)({
51
51
  name: 'no-unnecessary-type-conversion',
@@ -689,8 +689,7 @@ exports.default = (0, util_1.createRule)({
689
689
  continue;
690
690
  }
691
691
  // skip ignored parameters
692
- if (def.name.type === utils_1.AST_NODE_TYPES.Identifier &&
693
- options.caughtErrorsIgnorePattern?.test(def.name.name)) {
692
+ if (options.caughtErrorsIgnorePattern?.test(def.name.name)) {
694
693
  if (options.reportUsedIgnorePattern && used) {
695
694
  report(variable, {
696
695
  messageId: 'usedIgnoredVar',
@@ -116,7 +116,7 @@ exports.default = (0, util_1.createRule)({
116
116
  paramSymbol.valueDeclaration.dotDotDotToken != null) {
117
117
  return;
118
118
  }
119
- if ((paramSymbol.flags & ts.SymbolFlags.Optional) === 0) {
119
+ if (!tsutils.isSymbolFlagSet(paramSymbol, ts.SymbolFlags.Optional)) {
120
120
  const paramType = checker.getTypeOfSymbol(paramSymbol);
121
121
  if (!canBeUndefined(paramType)) {
122
122
  reportUselessDefaultAssignment(node, 'parameter');
@@ -169,7 +169,7 @@ exports.default = (0, util_1.createRule)({
169
169
  if (!symbol) {
170
170
  return null;
171
171
  }
172
- if (symbol.flags & ts.SymbolFlags.Optional &&
172
+ if (tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Optional) &&
173
173
  hasConditionalInitializer(objectPattern)) {
174
174
  return null;
175
175
  }
@@ -63,7 +63,7 @@ exports.default = (0, util_1.createRule)({
63
63
  return tsutils.unionConstituents(type);
64
64
  };
65
65
  const couldBeNullish = (type) => {
66
- if (type.flags & ts.TypeFlags.TypeParameter) {
66
+ if (tsutils.isTypeFlagSet(type, ts.TypeFlags.TypeParameter)) {
67
67
  const constraint = type.getConstraint();
68
68
  return constraint == null || couldBeNullish(constraint);
69
69
  }
@@ -75,10 +75,10 @@ exports.default = (0, util_1.createRule)({
75
75
  }
76
76
  return false;
77
77
  }
78
- return (type.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) !== 0;
78
+ return tsutils.isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined);
79
79
  };
80
80
  const sameTypeWithoutNullish = (assertedTypes, originalTypes) => {
81
- const nonNullishOriginalTypes = originalTypes.filter(type => (type.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) === 0);
81
+ const nonNullishOriginalTypes = originalTypes.filter(type => !tsutils.isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined));
82
82
  if (nonNullishOriginalTypes.length === originalTypes.length) {
83
83
  return false;
84
84
  }
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const utils_1 = require("@typescript-eslint/utils");
37
+ const tsutils = __importStar(require("ts-api-utils"));
37
38
  const ts_api_utils_1 = require("ts-api-utils");
38
39
  const ts = __importStar(require("typescript"));
39
40
  const util_1 = require("../util");
@@ -133,7 +134,7 @@ exports.default = (0, util_1.createRule)({
133
134
  if ((0, util_1.typeMatchesSomeSpecifier)(type, allow, services.program)) {
134
135
  return;
135
136
  }
136
- if (type.flags & ts.TypeFlags.Undefined) {
137
+ if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Undefined)) {
137
138
  context.report({ node, messageId: 'undef' });
138
139
  return;
139
140
  }
@@ -131,8 +131,7 @@ exports.default = util.createRule({
131
131
  * @returns `true` if the expected type was void function.
132
132
  */
133
133
  function checkExpressionNode(node) {
134
- const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
135
- const expectedType = checker.getContextualType(tsNode);
134
+ const expectedType = parserServices.getContextualType(node);
136
135
  if (expectedType != null && isVoidReturningFunctionType(expectedType)) {
137
136
  reportIfNonVoidFunction(node);
138
137
  return true;
@@ -206,8 +205,7 @@ exports.default = util.createRule({
206
205
  // Don't check object methods with computed name.
207
206
  return;
208
207
  }
209
- const objTsNode = propTsNode.parent;
210
- const objType = checker.getContextualType(objTsNode);
208
+ const objType = parserServices.getContextualType(propNode.parent);
211
209
  if (objType == null) {
212
210
  // Expected object type is unknown.
213
211
  return;
@@ -57,8 +57,7 @@ function findTruthinessAssertedArgument(services, node) {
57
57
  return undefined;
58
58
  }
59
59
  const checker = services.program.getTypeChecker();
60
- const tsNode = services.esTreeNodeToTSNodeMap.get(node);
61
- const signature = checker.getResolvedSignature(tsNode);
60
+ const signature = services.getResolvedSignature(node);
62
61
  if (signature == null) {
63
62
  return undefined;
64
63
  }
@@ -92,8 +91,7 @@ function findTypeGuardAssertedArgument(services, node) {
92
91
  return undefined;
93
92
  }
94
93
  const checker = services.program.getTypeChecker();
95
- const tsNode = services.esTreeNodeToTSNodeMap.get(node);
96
- const callSignature = checker.getResolvedSignature(tsNode);
94
+ const callSignature = services.getResolvedSignature(node);
97
95
  if (callSignature == null) {
98
96
  return undefined;
99
97
  }
@@ -318,6 +318,20 @@ class ThisScope extends scope_manager_1.Visitor {
318
318
  /////////////////////
319
319
  // Visit selectors //
320
320
  /////////////////////
321
+ AssignmentExpression(node) {
322
+ this.visitChildren(node);
323
+ if (node.right.type === utils_1.AST_NODE_TYPES.ThisExpression &&
324
+ node.left.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
325
+ this.handleThisDestructuring(node.left);
326
+ }
327
+ }
328
+ AssignmentPattern(node) {
329
+ this.visitChildren(node);
330
+ if (node.right.type === utils_1.AST_NODE_TYPES.ThisExpression &&
331
+ node.left.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
332
+ this.handleThisDestructuring(node.left);
333
+ }
334
+ }
321
335
  ClassDeclaration(node) {
322
336
  this.visitClass(node);
323
337
  }
@@ -391,6 +405,39 @@ class ThisScope extends scope_manager_1.Visitor {
391
405
  StaticBlock(node) {
392
406
  this.visitIntermediate(node);
393
407
  }
408
+ VariableDeclarator(node) {
409
+ this.visitChildren(node);
410
+ if (node.init?.type === utils_1.AST_NODE_TYPES.ThisExpression &&
411
+ node.id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
412
+ this.handleThisDestructuring(node.id);
413
+ }
414
+ }
415
+ /**
416
+ * Handles destructuring from `this` in ObjectPattern.
417
+ * Example: const { property } = this;
418
+ */
419
+ handleThisDestructuring(pattern) {
420
+ if (this.thisContext == null) {
421
+ return;
422
+ }
423
+ for (const prop of pattern.properties) {
424
+ if (prop.type !== utils_1.AST_NODE_TYPES.Property) {
425
+ continue;
426
+ }
427
+ if (prop.key.type !== utils_1.AST_NODE_TYPES.Identifier || prop.computed) {
428
+ continue;
429
+ }
430
+ const memberKey = (0, types_1.publicKey)(prop.key.name);
431
+ const members = this.isStaticThisContext
432
+ ? this.thisContext.members.static
433
+ : this.thisContext.members.instance;
434
+ const member = members.get(memberKey);
435
+ if (member == null) {
436
+ continue;
437
+ }
438
+ countReference(prop.key, member);
439
+ }
440
+ }
394
441
  }
395
442
  /**
396
443
  * Any other scope that is not a class scope
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typescript-eslint/eslint-plugin",
3
- "version": "8.53.2-alpha.1",
3
+ "version": "8.53.2-alpha.10",
4
4
  "description": "TypeScript plugin for ESLint",
5
5
  "files": [
6
6
  "dist",
@@ -59,10 +59,10 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@eslint-community/regexpp": "^4.12.2",
62
- "@typescript-eslint/scope-manager": "8.53.2-alpha.1",
63
- "@typescript-eslint/type-utils": "8.53.2-alpha.1",
64
- "@typescript-eslint/utils": "8.53.2-alpha.1",
65
- "@typescript-eslint/visitor-keys": "8.53.2-alpha.1",
62
+ "@typescript-eslint/scope-manager": "8.53.2-alpha.10",
63
+ "@typescript-eslint/type-utils": "8.53.2-alpha.10",
64
+ "@typescript-eslint/utils": "8.53.2-alpha.10",
65
+ "@typescript-eslint/visitor-keys": "8.53.2-alpha.10",
66
66
  "ignore": "^7.0.5",
67
67
  "natural-compare": "^1.4.0",
68
68
  "ts-api-utils": "^2.4.0"
@@ -70,8 +70,8 @@
70
70
  "devDependencies": {
71
71
  "@types/mdast": "^4.0.4",
72
72
  "@types/natural-compare": "*",
73
- "@typescript-eslint/rule-schema-to-typescript-types": "8.53.2-alpha.1",
74
- "@typescript-eslint/rule-tester": "8.53.2-alpha.1",
73
+ "@typescript-eslint/rule-schema-to-typescript-types": "8.53.2-alpha.10",
74
+ "@typescript-eslint/rule-tester": "8.53.2-alpha.10",
75
75
  "@vitest/coverage-v8": "^3.2.4",
76
76
  "ajv": "^6.12.6",
77
77
  "eslint": "*",
@@ -81,7 +81,7 @@
81
81
  "mdast-util-from-markdown": "^2.0.2",
82
82
  "mdast-util-mdx": "^3.0.0",
83
83
  "micromark-extension-mdxjs": "^3.0.0",
84
- "prettier": "3.7.4",
84
+ "prettier": "3.8.0",
85
85
  "rimraf": "*",
86
86
  "title-case": "^4.3.2",
87
87
  "tsx": "*",
@@ -90,7 +90,7 @@
90
90
  "vitest": "^3.2.4"
91
91
  },
92
92
  "peerDependencies": {
93
- "@typescript-eslint/parser": "^8.53.2-alpha.1",
93
+ "@typescript-eslint/parser": "^8.53.2-alpha.10",
94
94
  "eslint": "^8.57.0 || ^9.0.0",
95
95
  "typescript": ">=4.8.4 <6.0.0"
96
96
  },