diff --git a/memoize/index.ts b/memoize/index.ts new file mode 100644 index 0000000..e9cfb16 --- /dev/null +++ b/memoize/index.ts @@ -0,0 +1,14 @@ +/** + * Returns a function that will memoize the return values for arguments of (pure) function f and return those on subsequent calls. + * Note that it only supports functions with exactly 1 argument and the values must be equatable (e.g., objects won't work) + */ +export const memoize = (f: (arg: T) => R): (arg: T) => R => { + const values = new Map() + return (arg: T) => { + if(!values.has(arg)) { + values.set(arg, f(arg)) + } + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return values.get(arg)! + } +} diff --git a/memoize/memoize.test.ts b/memoize/memoize.test.ts new file mode 100644 index 0000000..f9d6816 --- /dev/null +++ b/memoize/memoize.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, test } from 'vitest' +import { memoize } from './index.js' + +describe('memoize', () => { + + test('delegates to function of first call', () => { + const mf = memoize((n: number) => n * 2) + expect(mf(2)).toEqual(4) + }) + + test('uses memoized return value on subsequent calls', () => { + let calls = 0 + const mf = memoize((n: number) => { + calls++ + return n * 2 + }) + + expect(mf(2)).toEqual(4) + expect(mf(2)).toEqual(4) + expect(calls).toEqual(1) + }) + + test('memorizes return value pre argument', () => { + let calls = 0 + const mf = memoize((n: number) => { + calls++ + return n * 2 + }) + + expect(mf(2)).toEqual(4) + expect(mf(2)).toEqual(4) + + expect(mf(1)).toEqual(2) + expect(mf(1)).toEqual(2) + + expect(calls).toEqual(2) + }) +})