diff --git a/packages/eslint-plugin/src/rules/prefer-readonly.ts b/packages/eslint-plugin/src/rules/prefer-readonly.ts index 2c8ab3671be..280213dde0f 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly.ts @@ -68,7 +68,7 @@ export default util.createRule({ return; } - if (ts.isDeleteExpression(parent)) { + if (ts.isDeleteExpression(parent) || isDestructuringAssignment(node)) { classScope.addVariableModification(node); return; } @@ -108,6 +108,35 @@ export default util.createRule({ } } + function isDestructuringAssignment( + node: ts.PropertyAccessExpression, + ): boolean { + let current: ts.Node = node.parent; + + while (current) { + const parent = current.parent; + + if ( + ts.isObjectLiteralExpression(parent) || + ts.isArrayLiteralExpression(parent) || + ts.isSpreadAssignment(parent) || + (ts.isSpreadElement(parent) && + ts.isArrayLiteralExpression(parent.parent)) + ) { + current = parent; + } else if (ts.isBinaryExpression(parent)) { + return ( + parent.left === current && + parent.operatorToken.kind === ts.SyntaxKind.EqualsToken + ); + } else { + break; + } + } + + return false; + } + function isConstructor(node: TSESTree.Node): boolean { return ( node.type === AST_NODE_TYPES.MethodDefinition && diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts index 5b2a6687339..8d6ffbf0f7a 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly.test.ts @@ -220,6 +220,54 @@ ruleTester.run('prefer-readonly', rule, { this['computed'] = 1; } }`, + { + code: ` +class Foo { + private value: number = 0 + + bar(newValue: { value: number }) { + ({ value: this.value } = newValue); + return this.value; + } +} + `, + }, + { + code: ` +class Foo { + private value: Record = {}; + + bar(newValue: Record) { + ({ ...this.value } = newValue); + return this.value; + } +} + `, + }, + { + code: ` +class Foo { + private value: number[] = [] + + bar(newValue: number[]) { + [...this.value] = newValue; + return this.value; + } +} + `, + }, + { + code: ` +class Foo { + private value: number = 0; + + bar(newValue: number[]) { + [this.value] = newValue; + return this.value; + } +} + `, + }, ], invalid: [ {