// Taken from ts-try https://github.com/elmarx/ts-try /** * helper to test if an object is a Promise. * * Taken from https://github.com/ssnau/xkit/blob/master/util/is-promise.js, * as suggested by https://stackoverflow.com/questions/27746304/how-do-i-tell-if-an-object-is-a-promise * as is plausible considering https://promisesaplus.com/#point-53 */ function isPromiseLike(obj: unknown): obj is PromiseLike { return ( !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof (obj as any).then === 'function' ); } /** * Union type to wrap the original type T and allow Errors additionally */ export type Try = [T, null] | [null, E]; /** * simple function to turn a promise of type T to type [T, null] | [null,Error] * * i.e.: catch the error and return it as [null,err] */ function tryify( p: PromiseLike ): PromiseLike> { return p.then( (x: T) => [x, null], (err: E) => [null, err] ); } /** * tc wraps code that throws, and returns the result OR the error thrown * * it imitates the concept (though it's not a monad) of scala.util.Try — but try is a reserved keyword, so it's called tc */ export function tc( asyncBlock: () => PromiseLike ): PromiseLike>; export function tc(block: () => T): Try; export function tc( promise: PromiseLike ): PromiseLike>; export function tc( input: PromiseLike | (() => T | PromiseLike) ): Try | PromiseLike> { // if the input is a simple promise, a simple try-ify is enough if (isPromiseLike(input)) { return tryify(input); } // ok, the input is a (sync or async) function, we need to execute it try { const v = input(); // if block is an async function, try-ify the returned promise if (isPromiseLike(v)) { return tryify(v); } // if block is sync, the result is in v, so just return return [v, null]; } catch (err) { // execution of block threw (and it's obviously sync), so return the error return [null, err as E]; } } export function isError(e: unknown): e is Error { return e instanceof Error; }