Repository: sindresorhus/mem (ts)

Issue:
Memoized methods of the same instance are mixed
If two functions are decorated of the same instance, their memoized values get mixed with the latest version (`v9.0.0`).

Take for example:

```typescript
class TestClass {
	@memDecorator()
	fn1() {
		return 1;
	}

	@memDecorator()
	counter2() {
		return 2;
	}
}

const instance = new TestClass();
console.log(instance.fn1()); // prints 1
console.log(instance.fn2()); // also prints 1 !!!
```

I would expect the second call to return 2, but it returns 1.

The memoized function in my understanding should be connected 1:1 to the _combination_ of _instance_ and _propterty_, whereas it is currently connected 1:1 to _instances_ (#74).

I guess a little bit more complicated internal data structure is needed instead of the current implementation of `decoratorInstanceMap`, will open a PR that adds a test and demonstrates a possible solution.

Pull request description:
Fix using multiple decorators on the same instance
Fixes #77

Patch:
diff --git a/index.ts b/index.ts
index ade4c63..9bbc8ba 100644
--- a/index.ts
+++ b/index.ts
@@ -3,8 +3,6 @@ import mapAgeCleaner from 'map-age-cleaner';
 
 type AnyFunction = (...arguments_: any) => any;
 
-const decoratorInstanceMap = new WeakMap();
-
 const cacheStore = new WeakMap<AnyFunction, CacheStorage<any, any>>();
 
 interface CacheStorageContent<ValueType> {
@@ -169,6 +167,8 @@ export function memDecorator<
 >(
 	options: Options<FunctionToMemoize, CacheKeyType> = {},
 ) {
+	const instanceMap = new WeakMap();
+
 	return (
 		target: any,
 		propertyKey: string,
@@ -184,13 +184,13 @@ export function memDecorator<
 		delete descriptor.writable;
 
 		descriptor.get = function () {
-			if (!decoratorInstanceMap.has(this)) {
+			if (!instanceMap.has(this)) {
 				const value = mem(input, options) as FunctionToMemoize;
-				decoratorInstanceMap.set(this, value);
+				instanceMap.set(this, value);
 				return value;
 			}
 
-			return decoratorInstanceMap.get(this) as FunctionToMemoize;
+			return instanceMap.get(this) as FunctionToMemoize;
 		};
 	};
 }


Test patch:
diff --git a/test.ts b/test.ts
index 63deaa5..23c68a8 100644
--- a/test.ts
+++ b/test.ts
@@ -239,19 +239,24 @@ test('prototype support', t => {
 
 test('.decorator()', t => {
 	let returnValue = 1;
+	const returnValue2 = 101;
 
 	class TestClass {
 		@memDecorator()
 		counter() {
-			return returnValue;
+			return returnValue++;
+		}
+
+		@memDecorator()
+		counter2() {
+			return returnValue2;
 		}
 	}
 
 	const alpha = new TestClass();
 	t.is(alpha.counter(), 1);
 	t.is(alpha.counter(), 1, 'The method should be memoized');
-
-	returnValue++;
+	t.is(alpha.counter2(), 101, 'The method should be memoized separately from the other one');
 
 	const beta = new TestClass();
 	t.is(beta.counter(), 2, 'The method should not be memoized across instances');