diff --git a/polyfill.d.ts b/polyfill.d.ts index 9c590db..1bcc1bb 100644 --- a/polyfill.d.ts +++ b/polyfill.d.ts @@ -56,12 +56,38 @@ interface ResultConstructor { /** * Creates a result for a successful operation */ - ok(value: V): Result + ok(this: void, value: V): Result /** * Creates a result for a failed operation */ - error(error: unknown): Result + error(this: void, error: unknown): Result + + /** + * Runs a function and wraps the result into a {@linkcode Result}. + * + * @example + * + * const [ok, error, value] = Result.try(func, arg1, arg2) + * const [ok, error, value] = await Result.try(asyncFunc, arg1, arg2) + * const [ok, error, value] = await Result.try(async (arg) => arg, 'pass') + */ + try R, A extends unknown[], R>( + this: void, + fn: F + ): R extends Promise ? Promise> : Result + + /** + * Wraps a promise into a {@linkcode Result}. + * + * The resulting promise never rejects. + * + * @example + * + * const [ok, error, value] = await Result.try(Promise.resolve('pass')) + * const [ok, error, value] = await Result.try(new Promise((rej) => rej('hello'))) + */ + try

, R>(this: void, promise: P): Promise> } declare const Result: ResultConstructor diff --git a/polyfill.js b/polyfill.js index 94fd3d4..8c7aea9 100644 --- a/polyfill.js +++ b/polyfill.js @@ -21,4 +21,22 @@ class Result { static error(error) { return new Result(false, error, undefined) } + + static try(fnOrPromise, ...args) { + if (fnOrPromise instanceof Promise) { + return fnOrPromise.then(Result.ok, Result.error) + } + + try { + const result = fnOrPromise.apply(undefined, args) + + if (result instanceof Promise) { + return result.then(Result.ok, Result.error) + } + + return Result.ok(result) + } catch (error) { + return Result.error(error) + } + } }