Skip to content

Instantly share code, notes, and snippets.

@bryanmylee
Last active August 16, 2023 06:19
Show Gist options
  • Save bryanmylee/564a872a16db330f716bf6e21a791f7e to your computer and use it in GitHub Desktop.
Save bryanmylee/564a872a16db330f716bf6e21a791f7e to your computer and use it in GitHub Desktop.
Handle errors more declaratively without try catch
/* eslint-disable @typescript-eslint/no-explicit-any */
export type Result<T, E> = [T, undefined] | [undefined, E];
/**
* Handle errors more declaratively without try catch.
*
* ```
* try {
* const res = doSomething(30);
* } catch (err) {
* console.log(err);
* }
* // becomes
* const [res, err] = tryResult(doSomething)(30);
* ```
*
* @param fn A throwable function to run.
* @returns A wrapped function that returns a Result enumeration.
*/
export function tryResult<A extends unknown[], T>(
fn: (...args: A) => T
): T extends Promise<infer R>
? (...args: A) => Promise<Result<R, NonNullable<unknown>>>
: (...args: A) => Result<T, NonNullable<unknown>> {
return ((...args: A) => {
try {
const result = fn(...args);
if (isPromise(result)) {
return result
.then((val) => [val, undefined])
.catch((err) => [undefined, err]);
}
return [result, undefined];
} catch (err) {
return [undefined, err];
}
}) as any;
}
function isPromise(value: unknown): value is Promise<unknown> {
return value != null && typeof value === "object" && "then" in value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment