diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index 8ec63de10dc6..518a696911b7 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -439,6 +439,8 @@ function isExported(variable: TSESLint.Scope.Variable): boolean { }); } +const LOGICAL_ASSIGNMENT_OPERATORS = new Set(['&&=', '||=', '??=']); + /** * Determines if the variable is used. * @param variable The variable to check. @@ -701,6 +703,7 @@ function isUsedVariable(variable: TSESLint.Scope.Variable): boolean { ref.isRead() && // in RHS of an assignment for itself. e.g. `a = a + 1` // self update. e.g. `a += 1`, `a++` ((parent.type === AST_NODE_TYPES.AssignmentExpression && + !LOGICAL_ASSIGNMENT_OPERATORS.has(parent.operator) && grandparent.type === AST_NODE_TYPES.ExpressionStatement && parent.left === id) || (parent.type === AST_NODE_TYPES.UpdateExpression && diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts index 636e2fe8d2c1..baed3954060c 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts @@ -1099,6 +1099,18 @@ interface Foo { bar: string; } `, + ` +let foo = 1; +foo ??= 2; + `, + ` +let foo = 1; +foo &&= 2; + `, + ` +let foo = 1; +foo ||= 2; + `, ], invalid: [ @@ -1844,5 +1856,23 @@ const Foo = 'bar'; }, ], }, + { + code: ` +let foo = 1; +foo += 1; + `, + errors: [ + { + messageId: 'unusedVar', + line: 3, + column: 1, + data: { + varName: 'foo', + action: 'assigned a value', + additional: '', + }, + }, + ], + }, ], });