Last active
December 18, 2024 16:15
-
-
Save christophemarois/b22b71b0aafe4814228cfaa4cc2e53f3 to your computer and use it in GitHub Desktop.
tryit.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// adapted from https://jsr.io/@backend/safe-assignment | |
type WithErrResultPlain<T> = [Error, null] | [null, T] | |
type WithErrResult<T> = T extends Promise<infer U> | |
? Promise<WithErrResultPlain<U>> | |
: WithErrResultPlain<T> | |
type WithErr<T> = T extends Promise<unknown> | |
? WithErrResult<T> | |
: T extends () => infer U | |
? WithErrResult<U> | |
: never | |
function wrapErr(err: unknown) { | |
if (err instanceof Error) { | |
return err | |
} | |
let message: string | |
try { | |
message = JSON.stringify(err) | |
} catch (err) { | |
message = `(failed to JSON.stringify) ${err}` | |
} | |
return new Error(`Non-error object was thrown or rejected: ${err}`) | |
} | |
function handleProm<T extends Promise<unknown>>( | |
p: Promise<T> | |
): Promise<WithErrResultPlain<T>> { | |
return p.then<WithErrResultPlain<T>, WithErrResultPlain<T>>( | |
(r) => [null, r], | |
(err) => [wrapErr(err), null] | |
) | |
} | |
/** | |
* Safely run a sync or async function and return an [Error?, Value?] tuple. | |
* Never fails. | |
* | |
* @example | |
* const [err, val] = tryit(() => {}); // sync | |
* const [err, val] = await tryit(async () => {}); // async | |
* const [err, val] = await tryit(promise); // existing promise | |
*/ | |
export function tryit<T extends (() => unknown) | Promise<unknown>>( | |
fnOrProm: T | |
): WithErr<T> { | |
if (fnOrProm instanceof Promise) { | |
return handleProm(fnOrProm) as WithErr<T> | |
} | |
try { | |
const r = fnOrProm() | |
if (r instanceof Promise) return handleProm(r) as WithErr<T> | |
return [null, r] as WithErr<T> | |
} catch (err) { | |
return [wrapErr(err), null] as WithErr<T> | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment