diff --git a/packages/eslint-plugin/src/rules/unbound-method.ts b/packages/eslint-plugin/src/rules/unbound-method.ts index 1e9cb9131ad..629aec50cca 100644 --- a/packages/eslint-plugin/src/rules/unbound-method.ts +++ b/packages/eslint-plugin/src/rules/unbound-method.ts @@ -241,6 +241,9 @@ function isSafeUse(node: TSESTree.Node): boolean { case AST_NODE_TYPES.BinaryExpression: return ['instanceof', '==', '!=', '===', '!=='].includes(parent.operator); + case AST_NODE_TYPES.AssignmentExpression: + return parent.operator === '=' && node === parent.left; + case AST_NODE_TYPES.TSNonNullExpression: case AST_NODE_TYPES.TSAsExpression: case AST_NODE_TYPES.TSTypeAssertion: diff --git a/packages/eslint-plugin/tests/rules/unbound-method.test.ts b/packages/eslint-plugin/tests/rules/unbound-method.test.ts index 10f0b549762..733b81e16b1 100644 --- a/packages/eslint-plugin/tests/rules/unbound-method.test.ts +++ b/packages/eslint-plugin/tests/rules/unbound-method.test.ts @@ -147,6 +147,9 @@ ruleTester.run('unbound-method', rule, { "typeof ContainsMethods.boundStatic === 'function';", "typeof ContainsMethods.unboundStatic === 'function';", + + 'instance.unbound = () => {};', + 'instance.unbound = instance.unbound.bind(instance);', ].map(addContainsMethodsClass), ` interface RecordA { @@ -211,6 +214,15 @@ const x: OptionalMethod = {}; declare const myCondition: boolean; if (myCondition || x.mightBeDefined) { console.log('hello world'); +} + `, + // https://github.com/typescript-eslint/typescript-eslint/issues/1256 + ` +class A { + unbound(): void { + this.unbound = undefined; + this.unbound = this.unbound.bind(this); + } } `, ], @@ -336,5 +348,24 @@ const x = CommunicationError.prototype.foo; }, ], }, + { + code: ` +class Foo { + unbound() {} +} +const instance = new Foo(); + +let x; + +x = instance.unbound; // THIS SHOULD ERROR +instance.unbound = x; // THIS SHOULD NOT + `, + errors: [ + { + line: 9, + messageId: 'unbound', + }, + ], + }, ], });