Last active
April 15, 2025 13:55
-
-
Save christophemarois/b22b71b0aafe4814228cfaa4cc2e53f3 to your computer and use it in GitHub Desktop.
attempt.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
/** Make sure that an unknown object is an error. If it's not, wrap it in an | |
* error with a useful inspection message */ | |
export function ensureError(err: unknown): Error { | |
if (err instanceof Error) { | |
return err | |
} | |
let data: string | |
try { | |
data = JSON.stringify(err) | |
if (data.length > 256) { | |
data = data.slice(0, 255) + '…' | |
} | |
} catch (err) { | |
data = `(failed to JSON.stringify: "${err}") ` | |
} | |
return new Error(`Non-error object was thrown or rejected: ${data}`, { | |
cause: err, | |
}) | |
} | |
/** Result discriminated union */ | |
type Result<Ok, Err> = [Ok, null] | [null, Err] | |
/** Runs a sync/async function and wraps its result/error in a {@link Result} | |
* discriminated union. To be removed when | |
* https://github.com/arthurfiorette/proposal-try-operator is available */ | |
export function attempt<Ok, Err extends Error = Error>(fn: () => Ok) { | |
type AttemptReturnType<Ok, Err> = Ok extends Promise<infer ResolvedOk> | |
? Promise<Result<ResolvedOk, Err>> | |
: Result<Ok, Err> | |
try { | |
const result = fn() | |
if (result instanceof Promise) { | |
return result | |
.then((resolved) => [resolved, null]) | |
.catch((e) => { | |
return [null, ensureError(e)] | |
}) as AttemptReturnType<Ok, Err> | |
} else { | |
return [result, null] as AttemptReturnType<Ok, Err> | |
} | |
} catch (e) { | |
return [null, ensureError(e)] as AttemptReturnType<Ok, Err> | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment