Memoize function in typescript

I want to memoize a pure function in ts that's just a static export without class. Typescript-memoize seems to need a class for the decorator to work. Do I have to wrap my functions into a class and possibly use a singleton or is there a simpler way to pull off memoization?
14 Replies
Neto
Neto12mo ago
class Memo {
private map = new Map<unknown, unknown>();

memoize<T extends (...args: any[]) => any>(fn: T): T {
return ((...args: any[]) => {
const key = JSON.stringify([fn.toString(), args].join("__"));
if (this.map.has(key)) {
console.log("cache hit", key);
return this.map.get(key);
}
const result = fn(...args);
console.log("cache miss", key);
this.map.set(key, result);
return result;
}) as T;
}
}
class Memo {
private map = new Map<unknown, unknown>();

memoize<T extends (...args: any[]) => any>(fn: T): T {
return ((...args: any[]) => {
const key = JSON.stringify([fn.toString(), args].join("__"));
if (this.map.has(key)) {
console.log("cache hit", key);
return this.map.get(key);
}
const result = fn(...args);
console.log("cache miss", key);
this.map.set(key, result);
return result;
}) as T;
}
}
something like this?
const memo = new Memo();

memo.memoize((a: number, b: number) => a + b)(1, 2);
memo.memoize((a: number, b: number) => a + b)(1, 2);
memo.memoize((c: number, d: number) => c + d)(1, 2);
memo.memoize((a: number, b: number) => a + b)(1, 3);
memo.memoize((a: number, b: number) => a + b)(1, 2);
memo.memoize((c: string, d: string) => [c + d].join("__"))("a", "b");
memo.memoize((c: string, d: string) => [c + d].join("__"))("a", "b");
const memo = new Memo();

memo.memoize((a: number, b: number) => a + b)(1, 2);
memo.memoize((a: number, b: number) => a + b)(1, 2);
memo.memoize((c: number, d: number) => c + d)(1, 2);
memo.memoize((a: number, b: number) => a + b)(1, 3);
memo.memoize((a: number, b: number) => a + b)(1, 2);
memo.memoize((c: string, d: string) => [c + d].join("__"))("a", "b");
memo.memoize((c: string, d: string) => [c + d].join("__"))("a", "b");
Neto
Neto12mo ago
cyremur
cyremur12mo ago
yeah I think the part I'm uncertain about is it being a class and where to save the instance and map in my t3 app but I think I'll go with something like that thanks!
Neto
Neto12mo ago
you can create a context the map would be at the context root no need to "use a class for that"
Tom
Tom12mo ago
wait. im just confused. why would you need to memoize a pure function?
Neto
Neto12mo ago
heavy calculations, such as some pi digit or factorial
Fagner
Fagner12mo ago
(I think) the goal is to not execute the function again and again, so the result is always the same since the input is the same
Tom
Tom12mo ago
Oh so memorizing the results? Not the function itself?
Fagner
Fagner12mo ago
Yes I mean, that's what I think. instead of calling the function it'll check for the memoized data and return the output instead
Tom
Tom12mo ago
Ok. That makes more sense. Never mind
Fagner
Fagner12mo ago
:)
cyremur
cyremur12mo ago
for context: it's a pathfinding algorithm on a gameboard and I wouldn't want it to run on every render, so atm my approach is to save the result until a player makes another move just trying to find the most elegant approach for that also, my phone error corrected memoize to memorize in the title -.- So I ended up just throwing this into a .ts file. Is it bad practice to just use globals for this kinda stuff or is it really that simple? Seems to work fine for me... @nyx (Rustular DevRel)
let lastNumActions = 0;
let lastPathsDict = {};

export const getBestAvailablePathsDict = (game: GameState) => {
if (game.combatLog.length === lastNumActions) {
return lastPathsDict;
}
//
// lots of calculations
//
lastNumActions = game.combatLog.length;
lastPathsDict = pathsDict;
return pathsDict;
};
let lastNumActions = 0;
let lastPathsDict = {};

export const getBestAvailablePathsDict = (game: GameState) => {
if (game.combatLog.length === lastNumActions) {
return lastPathsDict;
}
//
// lots of calculations
//
lastNumActions = game.combatLog.length;
lastPathsDict = pathsDict;
return pathsDict;
};
Neto
Neto12mo ago
i mean, if it works its fine
cyremur
cyremur12mo ago
yeah lgtm thanks for the advice