mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
80 lines
2.7 KiB
TypeScript
80 lines
2.7 KiB
TypeScript
/**
|
|
* Safely try to execute a promise, returning a tuple of [error, result].
|
|
*
|
|
* If the promise rejects or an error is thrown, the error will be the first element of the tuple.
|
|
*
|
|
* If the promise resolves, the result will be the second element of the tuple.
|
|
*
|
|
* @note If the tuple error value is null, the promise was not rejected and no error was thrown.
|
|
* So the result value is guaranteed to be the promise's resolve value. (This can obviously be null
|
|
* if the promise resolves to null, so always check the error value for the success state.)
|
|
*
|
|
* @param promise - The promise to try to execute.
|
|
* @returns A tuple of [error, result].
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const [err, result] = await safeTry(Promise.resolve(42));
|
|
*
|
|
* console.log(result); // null or 42
|
|
*
|
|
* if (err) {
|
|
* console.error(err);
|
|
* return 'Not Found'
|
|
* }
|
|
*
|
|
* console.log(result); // 42
|
|
* return result;
|
|
* ```
|
|
*/
|
|
export async function safeTry<T, E = Error>(promise: Promise<T>): Promise<[null, T] | [E, null]> {
|
|
try {
|
|
const result = await promise;
|
|
return [null, result];
|
|
} catch (err) {
|
|
return [err as E, null];
|
|
}
|
|
}
|
|
|
|
type SyncFn<T> = (...args: Array<never>) => T extends Promise<unknown> ? never : T;
|
|
|
|
/**
|
|
* Safely try to execute a synchronous function, returning a tuple of [error, result].
|
|
*
|
|
* If the function throws an error, the error will be the first element of the tuple. Otherwise, it will be null.
|
|
*
|
|
* If the function returns a value, the result will be the second element of the tuple. Otherwise, it will be null.
|
|
*
|
|
* @note If the tuple error value is null, the function did not throw an error. So the result value
|
|
* is guaranteed to be the function's return value. (This can obviously be null if the function
|
|
* returns null, so always check the error value for the success state.)
|
|
*
|
|
* @note This function is only safe to use with synchronous functions. If you need to use
|
|
* a function that returns a promise, use {@link safeTry} instead. While calling an async
|
|
* function will give the result as a promise, the promise isn't internally awaited, so any errors
|
|
* will not be safely returned as a value (the `error` property will always be `null`). Any errors
|
|
* thrown by the function will be thrown as a synchronous exception.
|
|
*
|
|
* @param fn - The function to try to execute.
|
|
* @returns A tuple of [error, result].
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const [err, result] = safeTrySync(() => 42);
|
|
* if (err) {
|
|
* console.error(err);
|
|
* return 'Not Found';
|
|
* }
|
|
* return result; // 42
|
|
* ```
|
|
*/
|
|
export function safeTrySync<T, E = Error>(fn: SyncFn<T>): [null, T] | [E, null] {
|
|
try {
|
|
return [null, fn()];
|
|
} catch (err) {
|
|
return [err as E, null];
|
|
}
|
|
}
|
|
|
|
export type Try<T, E = Error> = Awaited<ReturnType<typeof safeTry<T, E>>>;
|