@typescript-eslint/eslint-plugin 8.70.1-alpha.16 → 8.70.1-alpha.18

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.
@@ -101,10 +101,6 @@ exports.default = (0, util_1.createRule)({
101
101
  });
102
102
  },
103
103
  "MethodDefinition[kind='constructor'] > FunctionExpression AssignmentExpression"(node) {
104
- const leftName = getPropertyName(node.left);
105
- if (!leftName) {
106
- return;
107
- }
108
104
  let functionNode = findParentFunction(node);
109
105
  if (functionNode && isArrowIIFE(functionNode)) {
110
106
  functionNode = findParentFunction(functionNode.parent);
@@ -113,6 +109,18 @@ exports.default = (0, util_1.createRule)({
113
109
  return;
114
110
  }
115
111
  const { assignedBeforeUnnecessary, unnecessaryAssignments } = (0, util_1.nullThrows)(reportInfoStack.at(reportInfoStack.length - 1), 'The top of stack should exist');
112
+ // A prior write to the parameter binding means a later `this.x = x`
113
+ // may copy a different value than the parameter property initialized.
114
+ if (node.left.type === utils_1.AST_NODE_TYPES.Identifier) {
115
+ if (isReferenceFromParameter(node.left)) {
116
+ assignedBeforeUnnecessary.add(node.left.name);
117
+ }
118
+ return;
119
+ }
120
+ const leftName = getPropertyName(node.left);
121
+ if (!leftName) {
122
+ return;
123
+ }
116
124
  if (!UNNECESSARY_OPERATORS.has(node.operator)) {
117
125
  assignedBeforeUnnecessary.add(leftName);
118
126
  return;
@@ -90,6 +90,19 @@ const SUPPORTED_GLOBAL_TYPES = [
90
90
  'Math',
91
91
  'JSON',
92
92
  ];
93
+ /**
94
+ * Methods on instances of built-in classes that are defined by the ECMAScript
95
+ * spec as *bound* to their instance (i.e. they are safe to call without their
96
+ * receiver), but whose TypeScript declarations don't model that binding - they
97
+ * are declared as plain methods that would require a `this` value.
98
+ *
99
+ * For example, `Intl.Collator.prototype.compare` is defined as a bound getter
100
+ * function per the ECMA-402 spec:
101
+ * https://tc39.es/ecma402/#sec-intl.collator.prototype.compare
102
+ * ...but `lib.es5.d.ts` declares it as a regular method, so this rule would
103
+ * otherwise incorrectly flag usages such as `array.sort(collator.compare)`.
104
+ */
105
+ const nativelyBoundInstanceMethods = new Set(['Collator.compare']);
93
106
  const isNotImported = (symbol, currentSourceFile) => {
94
107
  const { valueDeclaration } = symbol;
95
108
  if (!valueDeclaration) {
@@ -99,6 +112,18 @@ const isNotImported = (symbol, currentSourceFile) => {
99
112
  return (!!currentSourceFile &&
100
113
  currentSourceFile !== valueDeclaration.getSourceFile());
101
114
  };
115
+ /**
116
+ * Returns `true` if `propertyName` is a member of a built-in class instance
117
+ * that is defined by the spec as bound to that instance (see
118
+ * `nativelyBoundInstanceMethods` above).
119
+ */
120
+ function isSpecBoundBuiltinMethod(program, objectType, propertyName) {
121
+ const symbol = objectType.getSymbol();
122
+ if (!symbol || !(0, util_1.isSymbolFromDefaultLibrary)(program, symbol)) {
123
+ return false;
124
+ }
125
+ return nativelyBoundInstanceMethods.has(`${symbol.getName()}.${propertyName}`);
126
+ }
102
127
  const BASE_MESSAGE = [
103
128
  `A method that is not declared with \`this: void\` may cause unintentional scoping of \`this\` when separated from its object.`,
104
129
  `Consider using an arrow function or explicitly \`.bind()\`ing the method to avoid calling the method with an unintended \`this\` value. `,
@@ -196,6 +221,12 @@ exports.default = (0, util_1.createRule)({
196
221
  return true;
197
222
  }
198
223
  }
224
+ if (property.type === utils_1.AST_NODE_TYPES.Identifier) {
225
+ const objectType = services.getTypeAtLocation(object);
226
+ if (isSpecBoundBuiltinMethod(services.program, objectType, property.name)) {
227
+ return true;
228
+ }
229
+ }
199
230
  // if `${object.name}.${property.name}` doesn't match any of
200
231
  // the nativelyBoundMembers, then we fallback to type-level checks
201
232
  return ((0, util_1.isBuiltinSymbolLike)(services.program, services.getTypeAtLocation(object), SUPPORTED_GLOBAL_TYPES) &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typescript-eslint/eslint-plugin",
3
- "version": "8.70.1-alpha.16",
3
+ "version": "8.70.1-alpha.18",
4
4
  "description": "TypeScript plugin for ESLint",
5
5
  "files": [
6
6
  "dist",
@@ -47,10 +47,10 @@
47
47
  ],
48
48
  "dependencies": {
49
49
  "@eslint-community/regexpp": "^4.12.2",
50
- "@typescript-eslint/scope-manager": "8.70.1-alpha.16",
51
- "@typescript-eslint/type-utils": "8.70.1-alpha.16",
52
- "@typescript-eslint/utils": "8.70.1-alpha.16",
53
- "@typescript-eslint/visitor-keys": "8.70.1-alpha.16",
50
+ "@typescript-eslint/scope-manager": "8.70.1-alpha.18",
51
+ "@typescript-eslint/type-utils": "8.70.1-alpha.18",
52
+ "@typescript-eslint/utils": "8.70.1-alpha.18",
53
+ "@typescript-eslint/visitor-keys": "8.70.1-alpha.18",
54
54
  "ignore": "^7.0.5",
55
55
  "natural-compare": "^1.4.0",
56
56
  "ts-api-utils": "^2.5.0"
@@ -60,8 +60,8 @@
60
60
  "@types/mdast": "^4.0.4",
61
61
  "@types/natural-compare": "^1.4.3",
62
62
  "@types/react": "^18.3.21",
63
- "@typescript-eslint/rule-schema-to-typescript-types": "8.70.1-alpha.16",
64
- "@typescript-eslint/rule-tester": "8.70.1-alpha.16",
63
+ "@typescript-eslint/rule-schema-to-typescript-types": "8.70.1-alpha.18",
64
+ "@typescript-eslint/rule-tester": "8.70.1-alpha.18",
65
65
  "@typescript/native": "npm:typescript@^7.0.2",
66
66
  "@vitest/coverage-v8": "^4.0.18",
67
67
  "ajv": "^6.12.6",
@@ -81,7 +81,7 @@
81
81
  "vitest": "^4.0.18"
82
82
  },
83
83
  "peerDependencies": {
84
- "@typescript-eslint/parser": "^8.70.1-alpha.16",
84
+ "@typescript-eslint/parser": "^8.70.1-alpha.18",
85
85
  "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
86
86
  "typescript": ">=4.8.4 <6.1.0"
87
87
  },