Skip to content

Instantly share code, notes, and snippets.

@remojansen
Last active August 15, 2024 13:26
Show Gist options
  • Save remojansen/f345ea7a266cb24b4b7c4773a329c64f to your computer and use it in GitHub Desktop.
Save remojansen/f345ea7a266cb24b4b7c4773a329c64f to your computer and use it in GitHub Desktop.
"attempt" TypeScript "try" utility
class Result<T, E = Error> {
constructor(
private v: T | undefined,
private e: E | undefined
) {}
onSuccess(cb: (v: T) => void) {
if (this.v !== undefined) {
cb(this.v as T);
}
}
onError(cb: (e: E) => void) {
if (this.e !== undefined) {
cb(this.e as E);
}
}
get value() {
return [this.v, this.e] as [T | undefined, E | undefined];
}
}
type AttemptCallback<T> = (() => T) | (() => Promise<T>);
type AttemptResult<Cb extends AttemptCallback<any>> =
Cb extends () => Promise<infer T>
? Promise<Result<T, Error>>
: Cb extends () => infer T ? Result<T, Error>: never
type t1 = AttemptResult<() => number>;
type t2 = AttemptResult<() => Promise<number>>;
function isPromise<T>(obj: any): obj is Promise<T> {
return obj && typeof obj === 'object' && typeof obj.then === 'function';
}
export function attempt<T, TCb extends AttemptCallback<T>>(cb: TCb): AttemptResult<typeof cb> {
let result: T| Promise<T> | null = null;
try {
result = cb();
if (isPromise<T>(result)) {
return result.then(v => new Result(v, undefined)).catch(e => new Result(undefined, e)) as AttemptResult<typeof cb>;
} else {
result
return new Result<T, Error>(result, undefined) as AttemptResult<typeof cb>;
}
} catch(e) {
return new Result(undefined, e) as AttemptResult<typeof cb>;
}
}
import { attempt } from "./lib.ts";
// Demo sync task with potential failure
function mightFail(): number {
const randomValue = Math.random();
const failureThreshold = 0.5; // 50% chance to fail
if (randomValue < failureThreshold) {
throw new Error("Something went wrong!");
} else {
return randomValue;
}
}
// Demo async task with potential failure
async function asyncMightFail() {
return new Promise<number>((resolve, reject) => {
try {
const result = mightFail();
resolve(result);
} catch(e) {
reject(e);
}
});
}
function testSync() {
const syncResult = attempt(mightFail);
const [result, error] = syncResult.value;
console.log(result, error);
syncResult.onSuccess(console.log);
syncResult.onError(console.error);
}
async function testAsync() {
const asyncResult = await attempt(asyncMightFail);
const [result, error] = asyncResult.value;
console.log(result, error);
asyncResult.onSuccess(console.log);
asyncResult.onError(console.error);
}
testSync();
testAsync();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment