Skip to content

Commit

Permalink
thrower-catch-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
uriva committed Feb 12, 2025
1 parent 71c0ad3 commit 293b949
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 31 deletions.
29 changes: 21 additions & 8 deletions src/debug.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Deno.test("tryCatch", () => {
const f = (x: number) => {
x = x + 3;
// @ts-expect-error should throw
return (7 + x.does.not.exist);
return 7 + x.does.not.exist;
};
assertThrows(() => {
f(3);
Expand All @@ -101,17 +101,30 @@ Deno.test("tryCatch async", async () => {
});

Deno.test("thrower catcher with value", async () => {
const [thrower, catcher] = throwerCatcherWithValue<string>();
const { thrower, catcher } = throwerCatcherWithValue<string>();
const expectation = "hello";
let result = "";
await catcher((x: string) => {
result = x;
return Promise.resolve();
}, () => {
const fAsync = (_: string) => {
thrower(expectation);
return Promise.resolve();
})();
return Promise.resolve("bla");
};
const fAsyncCaught = catcher((x: string) => {
result = x;
return Promise.resolve(7);
})(fAsync);
const _value: string | number = await fAsyncCaught("input");
assertEquals(result, expectation);
});

const { catcher } = throwerCatcherWithValue<string>();
const f = catcher((_: string) => 7)((_: string) => {
return Promise.resolve("bla");
});
// @ts-expect-error detects bad type, should be a string | number
const _badTyping: string = await f("hello");
// @ts-expect-error detects bad type, should be a Promise<string|number
const _detectAsync: string | number = f("hello there");
const _nonNotAsync: number | null = catcher(() => null)((_: string) => 1)(
"hello",
);
const _: () => Promise<string> = tryCatch(() => Promise.resolve(""), () => "");
56 changes: 33 additions & 23 deletions src/debug.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { pipe } from "./composition.ts";
import { pairRight } from "./juxt.ts";
import { isPromise } from "./promise.ts";
import { currentLocation } from "./trace.ts";
import type {
AsyncFunction,
Func,
IsAsync,
ParamOf,
ReturnTypeUnwrapped,
} from "./typing.ts";
import { pipe, sideEffect } from "./composition.ts";
import { pairRight } from "./juxt.ts";
import { isPromise } from "./promise.ts";
import { currentLocation } from "./trace.ts";
import { letIn } from "./operator.ts";

export const sideLog = <T>(x: T) => {
console.log(currentLocation(3), x);
Expand Down Expand Up @@ -162,31 +161,42 @@ export const throwerCatcher = () => {
return [thrower, catcher] as [typeof thrower, typeof catcher];
};

export const catchErrorWithIdAndValue = <T>(id: string) =>
// deno-lint-ignore no-explicit-any
<F extends AsyncFunction, G extends (value: T) => any>(
fallback: G,
f: F,
): (...args: Parameters<F>) => ReturnType<F> | ReturnType<G> =>
// @ts-expect-error cannot infer
async (...xs: Parameters<F>) => {
try {
return await f(...xs);
} catch (e) {
// @ts-ignore-error This code has a distinct type of `Error` (doesn't trigger in node)
if (e.id === id) return fallback(e.payload);
throw e;
}
};
type EitherOutput<F extends Func, G extends Func> = F extends AsyncFunction
? Promise<ReturnTypeUnwrapped<F> | ReturnTypeUnwrapped<G>>
: G extends AsyncFunction
? Promise<ReturnTypeUnwrapped<F> | ReturnTypeUnwrapped<G>>
: (ReturnTypeUnwrapped<F> | ReturnTypeUnwrapped<G>);

export const catchErrorWithIdAndValue =
(id: string) =>
<G extends Func>(fallback: G) =>
<F extends Func>(f: F) =>
(...xs: Parameters<F>): EitherOutput<F, G> => {
try {
const result = f(...xs);
if (isPromise(result)) {
// @ts-expect-error cannot infer
return result.catch((e) => {
if (e.id === id) return fallback(e.payload);
throw e;
});
}
return result;
} catch (e) {
// @ts-ignore-error This code has a distinct type of `Error` (doesn't trigger in node)
if (e.id === id) return fallback(e.payload);
throw e;
}
};

export const throwerCatcherWithValue = <T>() => {
const id = crypto.randomUUID();
const catcher = catchErrorWithIdAndValue<T>(id);
const catcher = catchErrorWithIdAndValue(id);
const thrower = (value: T) => {
const e = makeErrorWithId(id);
// @ts-expect-error This code has a distinct type of `Error`
e.payload = value;
throw e;
};
return [thrower, catcher] as [typeof thrower, typeof catcher];
return { thrower, catcher };
};

0 comments on commit 293b949

Please sign in to comment.