Skip to content

Commit

Permalink
Split function generic into generic types for args and return value (#61
Browse files Browse the repository at this point in the history
)
  • Loading branch information
wbinnssmith authored and alexreardon committed Apr 8, 2019
1 parent 04094ec commit cbde410
Showing 1 changed file with 15 additions and 15 deletions.
30 changes: 15 additions & 15 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,36 @@ const simpleIsEqual: EqualityFn = (
shallowEqual(newArg, lastArgs[index]),
);

// <ResultFn: (...any[]) => mixed>
// The purpose of this typing is to ensure that the returned memoized
// function has the same type as the provided function (`resultFn`).
// ResultFn: Generic type (which is the same as the resultFn).
// (...any[]): Accepts any length of arguments - and they are not checked
// mixed: The result can be anything but needs to be checked before usage
export default function<ResultFn: (...any[]) => mixed>(
resultFn: ResultFn,
// Type TArgs (arguments type) and TRet (return type) as generics to ensure that the
// returned function (`memoized`) has the same type as the provided function (`inputFn`).
//
// `mixed` means that the result can be anything but needs to be checked before usage.
// As opposed to `any`, it does not compromise type-safety.
// See https://flow.org/en/docs/types/mixed/ for more.
export default function memoizeOne<TArgs: mixed[], TRet: mixed>(
inputFn: (...TArgs) => TRet,
isEqual?: EqualityFn = simpleIsEqual,
): ResultFn {
): (...TArgs) => TRet {
let lastThis: mixed;
let lastArgs: mixed[] = [];
let lastResult: mixed;
let lastArgs: ?TArgs;
let lastResult: TRet; // not ?TRet because TRet must include undefined | null
let calledOnce: boolean = false;

// breaking cache when context (this) or arguments change
const result = function(...newArgs: mixed[]) {
if (calledOnce && lastThis === this && isEqual(newArgs, lastArgs)) {
const memoized = function(...newArgs: TArgs): TRet {
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);
lastResult = inputFn.apply(this, newArgs);
calledOnce = true;
lastThis = this;
lastArgs = newArgs;
return lastResult;
};

return (result: any);
return memoized;
}

0 comments on commit cbde410

Please sign in to comment.