In this guide, we'll present a handy TypeScript utility that can streamline your error handling process. This utility provides a simple and clear way to encapsulate potential errors and handle them gracefully.
Snippets are based on no-try npm package (link below).
The TypeScript utility is composed of two main functions, useTry
and useTryAsync
.
These two functions execute a given function and handle any potential errors that may be thrown. If an error occurs, it is caught and returned along with null
for the data. Conversely, if no error is thrown, the function's return data is returned along with null
for the error.
The type NoTryResult<T, E>
represents the potential outcomes of this operation. The result will be either an error with no data ([E, null]
), or data with no error ([null, T]
).
Here is the TypeScript code snippet:
export type NoTryResult<T, E = Error> = [E, null] | [null, T];
function noop(): null {
return null;
}
export function useTry<T, E = Error>(
fn: () => T,
handleErr: (error: E) => void = noop
): NoTryResult<T, E> {
try {
return [null, fn()];
} catch (err) {
handleErr(err as E);
return [err as E, null];
}
}
export async function useTryAsync<T, E = Error>(
fn: () => Promise<T>,
handleErr: (error: E) => void = noop
): Promise<NoTryResult<T, E>> {
try {
return [null, await fn()];
} catch (err) {
handleErr(err as E);
return [err as E, null];
}
}
Below is an example of how you could use these utilities:
const [error, data] = await useTryAsync(
() => fetchData(),
(e) => console.log(e) // Can be omitted
);
if (error) return;
handleUserData(data); // TypeScript understands `data` is not null
In the code snippet above, useTryAsync
tries to execute fetchData
. If fetchData
throws an error, the error is handled and returned. If fetchData
succeeds, the data is returned. The handleUserData
function is then safely called with the data.
Here is a version of the utility in vanilla JavaScript:
function noop() {
return null;
}
function useTry(fn, handleErr = noop) {
try {
return [null, fn()];
} catch (err) {
handleErr(err);
return [err, null];
}
}
async function useTryAsync(fn, handleErr = noop) {
try {
return [null, await fn()];
} catch (err) {
handleErr(err);
return [err, null];
}
}
Please note that due to the lack of TypeScript's static typing, the JavaScript version doesn't provide the same level of type safety as the TypeScript version.