41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import areInputsEqual from './are-inputs-equal';
|
|
|
|
// Using ReadonlyArray<T> rather than readonly T as it works with TS v3
|
|
export type EqualityFn = (newArgs: any[], lastArgs: any[]) => boolean;
|
|
|
|
function memoizeOne<
|
|
// Need to use 'any' rather than 'unknown' here as it has
|
|
// The correct Generic narrowing behaviour.
|
|
ResultFn extends (this: any, ...newArgs: any[]) => ReturnType<ResultFn>
|
|
>(resultFn: ResultFn, isEqual: EqualityFn = areInputsEqual): ResultFn {
|
|
let lastThis: unknown;
|
|
let lastArgs: unknown[] = [];
|
|
let lastResult: ReturnType<ResultFn>;
|
|
let calledOnce: boolean = false;
|
|
|
|
// breaking cache when context (this) or arguments change
|
|
function memoized(this: unknown, ...newArgs: unknown[]): ReturnType<ResultFn> {
|
|
if (calledOnce && lastThis === this && isEqual(newArgs, lastArgs)) {
|
|
return lastResult;
|
|
}
|
|
|
|
// Throwing during an assignment aborts the assignment: https://codepen.io/alexreardon/pen/RYKoaz
|
|
// Doing the lastResult assignment first so that if it throws
|
|
// nothing will be overwritten
|
|
lastResult = resultFn.apply(this, newArgs);
|
|
calledOnce = true;
|
|
lastThis = this;
|
|
lastArgs = newArgs;
|
|
return lastResult;
|
|
}
|
|
|
|
return memoized as ResultFn;
|
|
}
|
|
|
|
// default export
|
|
export default memoizeOne;
|
|
|
|
// disabled for now as mixing named and
|
|
// default exports is problematic with CommonJS
|
|
// export { memoizeOne };
|