When aiming for the desired functionality, the function should possess a specific type signature:
export const tryAsyncAwait = async <F extends () => any>(
fn: F
): Promise<[ReturnType<F>, null]> => {
try {
const data = await fn();
return [data, null];
} catch (error) {
return [null, error];
}
};
However, due to an alternative return
in the catch
block, the type needs to be a union of the resolved and rejected value to maintain accuracy.
export const tryAsyncAwait = async <F extends () => any>(
fn: F
): Promise<[ReturnType<F>, null] | [null, unknown]> => {
try {
const data = await fn();
return [data, null];
} catch (error) {
return [null, error];
}
};
Furthermore, it's crucial to remember that the return type must be enveloped within a Promise
since async
is utilized in the function definition. By awaiting the call to fn
, it implies that other async
functions can be accepted as callbacks. The broad type signature () => any
is inclusive enough to accommodate these scenarios.