import mimicFn from 'mimic-fn' ; import mapAgeCleaner from 'map-age-cleaner' ; type AnyFunction = ( ... arguments_ : any ) => any ; const cacheStore = new WeakMap < AnyFunction , CacheStorage < any , any > > ( ) ; interface CacheStorageContent < ValueType > { data : ValueType ; maxAge : number ; } interface CacheStorage < KeyType , ValueType > { has : ( key : KeyType ) => boolean ; get : ( key : KeyType ) => CacheStorageContent < ValueType > | undefined ; set : ( key : KeyType , value : CacheStorageContent < ValueType > ) => void ; delete : ( key : KeyType ) => void ; clear ? : ( ) => void ; } export interface Options < FunctionToMemoize extends AnyFunction , CacheKeyType > { default readonly maxAge ? : number ; default example readonly cacheKey ? : ( arguments_ : Parameters < FunctionToMemoize > ) => CacheKeyType ; default example readonly cache ? : CacheStorage < CacheKeyType , ReturnType < FunctionToMemoize > > ; } param fn example export default function mem < FunctionToMemoize extends AnyFunction , CacheKeyType > ( fn , { cacheKey , cache = new Map ( ) , maxAge , } = { } ) { if ( typeof maxAge === 'number' ) { mapAgeCleaner ( cache as unknown as Map < CacheKeyType , ReturnType < FunctionToMemoize > > ) ; } const memoized = function ( this , ... arguments_ ) : ReturnType < FunctionToMemoize > { const key = cacheKey ? cacheKey ( arguments_ ) : arguments_ [ 0 ] as CacheKeyType ; const cacheItem = cache . get ( key ) ; if ( cacheItem ) { return cacheItem . data ; } const result = fn . apply ( this , arguments_ ) as ReturnType < FunctionToMemoize > ; cache . set ( key , { data : result , maxAge : maxAge ? Date . now ( ) + maxAge : Number . POSITIVE_INFINITY , } ) ; return result ; } as FunctionToMemoize ; mimicFn ( memoized , fn , { ignoreNonConfigurable : true , } ) ; cacheStore . set ( memoized , cache ) ; return memoized ; } returns example memDecorator memDecorator export function memDecorator < FunctionToMemoize extends AnyFunction , CacheKeyType > ( options = { } ) { const instanceMap = new WeakMap ( ) ; return ( target , propertyKey , descriptor ) : void => { const input = target [ propertyKey ] ; if ( typeof input !== 'function' ) { throw new TypeError ( 'The decorated value must be a function' ) ; } delete descriptor . value ; delete descriptor . writable ; descriptor . get = function ( ) { if ( ! instanceMap . has ( this ) ) { const value = mem ( input , options ) as FunctionToMemoize ; instanceMap . set ( this , value ) ; return value ; } return instanceMap . get ( this ) as FunctionToMemoize ; } ; } ; } param fn export function memClear ( fn ) { const cache = cacheStore . get ( fn ) ; if ( ! cache ) { throw new TypeError ( 'Can\'t clear a function that was not memoized!' ) ; } if ( typeof cache . clear !== 'function' ) { throw new TypeError ( 'The cache Map can\'t be cleared!' ) ; } cache . clear ( ) ; }