Skip to content

Commit c579ca6

Browse files
committed
feat: spy() support having no callback
1 parent 2a7ec39 commit c579ca6

4 files changed

Lines changed: 58 additions & 8 deletions

File tree

.changeset/funky-comics-shave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@auaust/toolkit": patch
3+
---
4+
5+
`spy()` gracefully handles missing callbacks

src/functions/spy.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,42 @@
1-
export function spy<A extends any[], R, This>(
2-
fn: (this: This, ...args: A) => R,
3-
before?: ((this: This, ...args: A) => void) | null,
4-
after?: ((this: This, result: R, ...args: A) => void) | null
5-
): (this: This, ...args: A) => R {
6-
return function (this: This, ...args: A): R {
1+
export type SafeReturnType<F> = F extends (...args: any[]) => infer R
2+
? R
3+
: undefined;
4+
5+
export type SafeParameters<F> = F extends (...args: infer P) => any ? P : [];
6+
7+
export function spy<F extends (this: This, ...args: any[]) => any, This>(
8+
fn: F,
9+
before?: ((this: This, ...args: Parameters<F>) => void) | null,
10+
after?:
11+
| ((this: This, result: ReturnType<F>, ...args: Parameters<F>) => void)
12+
| null
13+
): (this: This, ...args: Parameters<F>) => ReturnType<F>;
14+
export function spy<
15+
F extends ((...args: any[]) => any) | null | undefined,
16+
This
17+
>(
18+
fn: F,
19+
before?: ((this: This, ...args: SafeParameters<F>) => void) | null,
20+
after?:
21+
| ((
22+
this: This,
23+
result: SafeReturnType<F>,
24+
...args: SafeParameters<F>
25+
) => void)
26+
| null
27+
): (this: This, ...args: SafeParameters<F>) => SafeReturnType<F>;
28+
export function spy(
29+
this: any,
30+
fn: any,
31+
before?: any,
32+
after?: any
33+
): (...args: any[]) => any {
34+
return function (this: any, ...args: any[]): any {
735
if (typeof before === "function") {
836
before.apply(this, args);
937
}
1038

11-
const result = fn.apply(this, args);
39+
const result = typeof fn === "function" ? fn.apply(this, args) : undefined;
1240

1341
if (typeof after === "function") {
1442
after.call(this, result, ...args);

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ export {
3333
type PipeEntry,
3434
} from "~/functions/pipe.js";
3535
export { sleep } from "~/functions/sleep.js";
36-
export { spy } from "~/functions/spy.js";
36+
export {
37+
spy,
38+
type SafeParameters,
39+
type SafeReturnType,
40+
} from "~/functions/spy.js";
3741
export { tap } from "~/functions/tap.js";
3842
export { throttle } from "~/functions/throttle.js";
3943
export { value, type Value } from "~/functions/value.js";

tests/functions/spy.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,17 @@ describe("spy()", () => {
6969

7070
expect(result).toBe(10);
7171
});
72+
73+
test("handles null or undefined closure gracefully", () => {
74+
const before = vi.fn();
75+
const after = vi.fn();
76+
77+
const spiedFunction = spy(null, before, after);
78+
79+
const result = spiedFunction();
80+
81+
expect(result).toBeUndefined();
82+
expect(before).toHaveBeenCalledWith();
83+
expect(after).toHaveBeenCalledWith(undefined);
84+
});
7285
});

0 commit comments

Comments
 (0)