From 48f991a98e3955a2ac32cc9a3b6f2ee5935aa3e6 Mon Sep 17 00:00:00 2001 From: Grzegorz Osimowicz Date: Wed, 14 Dec 2022 10:03:06 +0100 Subject: [PATCH] Allow to override bound methods --- __tests__/index.spec.ts | 40 +++++++++++++++++++++++++++++----------- src/index.ts | 13 ++++++++++++- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/__tests__/index.spec.ts b/__tests__/index.spec.ts index fe2dfdc..33d6369 100644 --- a/__tests__/index.spec.ts +++ b/__tests__/index.spec.ts @@ -59,28 +59,46 @@ describe('@bind', function () { }); describe('when used to bind to this context', function () { - it('binds decorated method to this context', function () { - class thisContext { - private test: string; + class thisContext { + protected test: string; - public constructor() { } + public constructor() { } - public getTest(): string { - return this.test; - } + public getTest(): string { + return this.test; + } - @bind - public setTest(test: string): void { - this.test = test; - } + @bind + public setTest(test: string): void { + this.test = test; } + } + it('binds decorated method to this context', function () { const tested: thisContext = new thisContext(); const { setTest } = tested; setTest('unit'); expect(tested.getTest()).toBe('unit'); }); + + + it('can be overwritten as well', function () { + class thisInheritedContext extends thisContext { + @bind + public setTest(inherited: string): void { + this.test = 'inherited ' + inherited; + } + } + + const tested: thisContext = new thisContext(); + tested.setTest('unit'); + expect(tested.getTest()).toBe('unit'); + + const inheritedTested: thisInheritedContext = new thisInheritedContext(); + inheritedTested.setTest('unit'); + expect(inheritedTested.getTest()).toBe('inherited unit'); + }); }); describe('when used to bind to static context', function () { diff --git a/src/index.ts b/src/index.ts index 6a67f7a..e81c46a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,21 @@ -export function bind(target: object, propertyKey: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor | void { +export function bind( + target: object, + propertyKey: string, + descriptor: TypedPropertyDescriptor +): TypedPropertyDescriptor | void { if(!descriptor || (typeof descriptor.value !== 'function')) { throw new TypeError(`Only methods can be decorated with @bind. <${propertyKey}> is not a method!`); } return { configurable: true, + set(value) { + Object.defineProperty(this, propertyKey, { + value: value, + configurable: true, + writable: true + }); + }, get(this: T): T { const bound: T = descriptor.value!.bind(this); // Credits to https://github.com/andreypopp/autobind-decorator for memoizing the result of bind against a symbol on the instance.