From ccfdc9c9dfaec0d5e3998353f719e0a88dac5fa6 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Sat, 22 Mar 2025 01:43:30 +0900 Subject: [PATCH 1/2] fix(eslint-plugin): [prefer-for-of] fix false positive when using non-null assertion within update expressions --- packages/eslint-plugin/src/util/isAssignee.ts | 8 ++++++++ .../tests/rules/prefer-for-of.test.ts | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/packages/eslint-plugin/src/util/isAssignee.ts b/packages/eslint-plugin/src/util/isAssignee.ts index 9bf694827722..df3e53d4885d 100644 --- a/packages/eslint-plugin/src/util/isAssignee.ts +++ b/packages/eslint-plugin/src/util/isAssignee.ts @@ -53,5 +53,13 @@ export function isAssignee(node: TSESTree.Node): boolean { return true; } + // a[i]!++, [...a[i]!] = [0], etc. + if ( + parent.type === AST_NODE_TYPES.TSNonNullExpression && + isAssignee(parent) + ) { + return true; + } + return false; } diff --git a/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts b/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts index 53a197f3f659..2d69ad0468dd 100644 --- a/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts @@ -139,6 +139,16 @@ for (let i = 0; i < arr.length; i++) { } `, ` +for (let i = 0; i < arr.length; i++) { + arr[i]++; +} + `, + ` +for (let i = 0; i < arr.length; i++) { + arr[i]!++; +} + `, + ` for (let i = 0; i < arr.length; i++) { [arr[i]] = [1]; } @@ -149,6 +159,11 @@ for (let i = 0; i < arr.length; i++) { } `, ` +for (let i = 0; i < arr.length; i++) { + [...arr[i]!] = [1]; +} + `, + ` for (let i = 0; i < arr.length; i++) { ({ foo: arr[i] }) = { foo: 0 }; } From c2c9d6ae5d14e0695cb1a23ff1f989b5655ae861 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Sun, 23 Mar 2025 12:57:00 +0900 Subject: [PATCH 2/2] fix(eslint-plugin): fix `isAssignee` function to handle any erasable type syntaxes --- packages/eslint-plugin/src/util/isAssignee.ts | 7 +++-- .../tests/rules/prefer-for-of.test.ts | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/util/isAssignee.ts b/packages/eslint-plugin/src/util/isAssignee.ts index df3e53d4885d..4183468ab4d9 100644 --- a/packages/eslint-plugin/src/util/isAssignee.ts +++ b/packages/eslint-plugin/src/util/isAssignee.ts @@ -53,9 +53,12 @@ export function isAssignee(node: TSESTree.Node): boolean { return true; } - // a[i]!++, [...a[i]!] = [0], etc. + // (a[i] as number)++, [...a[i]!] = [0], etc. if ( - parent.type === AST_NODE_TYPES.TSNonNullExpression && + (parent.type === AST_NODE_TYPES.TSNonNullExpression || + parent.type === AST_NODE_TYPES.TSAsExpression || + parent.type === AST_NODE_TYPES.TSTypeAssertion || + parent.type === AST_NODE_TYPES.TSSatisfiesExpression) && isAssignee(parent) ) { return true; diff --git a/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts b/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts index 2d69ad0468dd..edc0e13519c8 100644 --- a/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-for-of.test.ts @@ -149,6 +149,36 @@ for (let i = 0; i < arr.length; i++) { } `, ` +for (let i = 0; i < arr.length; i++) { + arr[i]!!!++; +} + `, + ` +for (let i = 0; i < arr.length; i++) { + (arr[i] as number)++; +} + `, + ` +for (let i = 0; i < arr.length; i++) { + (arr[i])++; +} + `, + ` +for (let i = 0; i < arr.length; i++) { + (arr[i] as unknown as number)++; +} + `, + ` +for (let i = 0; i < arr.length; i++) { + (arr[i] satisfies number)++; +} + `, + ` +for (let i = 0; i < arr.length; i++) { + (arr[i]! satisfies number)++; +} + `, + ` for (let i = 0; i < arr.length; i++) { [arr[i]] = [1]; }