Skip to content

Commit

Permalink
feat: preserves overloads for non-async functions (#22)
Browse files Browse the repository at this point in the history
* feat: preserves overloads for non-async functions

* chore: format types

* chore: use type cast on trace newFn

* chore: move declarations to trace demo file

* chore: use type cast for memoize

* chore: add memoize demo for overloaded functions

* chore: use type cast for als

* test: update als test type for incBy

---------

Co-authored-by: Rexford Essilfie <[email protected]>
  • Loading branch information
ahrjarrett and rexfordessilfie authored Feb 14, 2024
1 parent ca87e02 commit 9b0f4b9
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 24 deletions.
25 changes: 25 additions & 0 deletions demos/memoize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,29 @@ export function demo() {
console.log(tracedFib(10));
}

// Demo with overloaded functions

function myFn(a: boolean): string | number;
function myFn<T, U>(a: T, b: U): T | U;

function myFn(...args: unknown[]) {
if (!Array.isArray(args)) {
throw new Error("Invalid arguments");
}

if (typeof args[0] === "boolean") {
return "hello";
}

return args[0];
}

export function demo2() {
console.log("demo2");
const memoizedMyFn = memoize((...args: any[]) => args.slice().join())(myFn);
console.log(memoizedMyFn(5, 6));
console.log(memoizedMyFn(false));
}

demo();
demo2();
24 changes: 24 additions & 0 deletions demos/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,28 @@ export function demo() {
console.log(tracedAdd(3, 5));
}

// Demo with overloaded functions

function myFn(a: boolean): string | number;
function myFn<T, U>(a: T, b: U): T | U;

function myFn(...args: unknown[]) {
if (!Array.isArray(args)) {
throw new Error("Invalid arguments");
}

if (typeof args[0] === "boolean") {
return "hello";
}

return args[0];
}

export function demo2() {
const tracedMyFn = trace(myFn);
tracedMyFn(5, 6);
tracedMyFn(false);
}

demo();
demo2();
9 changes: 4 additions & 5 deletions src/common/als.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { Any } from "src/common/types";
import { AsyncLocalStorage } from "node:async_hooks";

export function als<T, IArgs extends any[]>(
storage: AsyncLocalStorage<T>,
init: (...args: IArgs) => T
) {
return function <FArgs extends IArgs, FReturn>(
fn: (...args: FArgs) => FReturn
) {
return function <Fn extends Any.Function>(fn: Fn) {
function newFn(...args: Parameters<typeof fn>) {
// @ts-ignore TS2683
// @ts-expect-error TS2683
const result = storage.run(init(...args), fn.bind(this), ...args);
return result;
}
Expand All @@ -20,6 +19,6 @@ export function als<T, IArgs extends any[]>(
}
);

return newFn;
return newFn as Fn;
};
}
12 changes: 7 additions & 5 deletions src/common/memoize.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
export function memoize<H extends (...args: any[]) => any>(
import { Any } from "src/common/types";

export function memoize<H extends Any.Function>(
hash: H,
cache = Object.create(null)
) {
return <FArgs extends any[], FReturn>(fn: (...args: FArgs) => FReturn) => {
return <Fn extends Any.Function>(fn: Fn) => {
function newFn(...args: Parameters<typeof fn>) {
// @ts-ignore TS2683
// @ts-expect-error TS2683
const key = hash.apply(this, args);
if (!(key in cache)) {
// @ts-ignore TS2683
// @ts-expect-error TS2683
cache[key] = fn.apply(this, args);
}
return cache[key] as ReturnType<typeof fn>;
Expand All @@ -20,6 +22,6 @@ export function memoize<H extends (...args: any[]) => any>(
}
);

return newFn;
return newFn as Fn;
};
}
12 changes: 6 additions & 6 deletions src/common/trace.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export const trace = <FArgs extends any[], FReturn>(
fn: (...args: FArgs) => FReturn
) => {
function newFn(...args: Parameters<typeof fn>) {
import type { Any } from "src/common/types";

export const trace = <Fn extends Any.Function>(fn: Fn) => {
function newFn(...args: Parameters<Fn>) {
const tag = `${fn.name}(${args}) | duration`;
console.time(tag);
// @ts-ignore TS2683
// @ts-expect-error TS2683
const result = fn.apply(this, args);
console.timeEnd(tag);
return result;
Expand All @@ -17,5 +17,5 @@ export const trace = <FArgs extends any[], FReturn>(
}
);

return newFn;
return newFn as Fn;
};
9 changes: 9 additions & 0 deletions src/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type { Any };

declare namespace Any {
type Function<I extends Array<unknown> = Array<any>, O = any> = {
(...args: I): O;
};
type Array<T = unknown> = ReadonlyArray<T>;
}

14 changes: 7 additions & 7 deletions src/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ type Spreadable<T> = T extends any[] ? T : never;

type Replace<Source, A, B, Sentinel = never> = Source extends Sentinel
? Omit<Source, keyof Sentinel> extends infer T
? Replace<LeftIfNotEqual<T, {}>, A, B, Sentinel> extends infer U
? U | B
: never // Dummy ternary just so we can get an alias T
: never // Dummy ternary just so we can get an alias U
? Replace<LeftIfNotEqual<T, {}>, A, B, Sentinel> extends infer U
? U | B
: never // Dummy ternary just so we can get an alias T
: never // Dummy ternary just so we can get an alias U
: Source extends Promise<infer T>
? Promise<Replace<T, A, B, Sentinel>>
: Source extends [infer AItem, ...infer ARest]
? [
Replace<AItem, A, B, Sentinel>,
...Spreadable<Replace<ARest, A, B, Sentinel>>
]
Replace<AItem, A, B, Sentinel>,
...Spreadable<Replace<ARest, A, B, Sentinel>>
]
: Source extends Record<string | number | symbol, any>
? { [K in keyof Source]: Replace<Source[K], A, B, Sentinel> }
: Source extends A
Expand Down
2 changes: 1 addition & 1 deletion test/als.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test("maintains reference to this", async (t) => {
incBy: als(
storage,
init
)(function (this: any) {
)(function (this: any, ..._args: any[]) {
return this.val + x();
}),
};
Expand Down

0 comments on commit 9b0f4b9

Please sign in to comment.