betterr
A better way to handle errors
Advantages
Unlike with try...catch or promises:
- Both data and errors are declared with const, available at the top level, and non-nullable (once the other is handled)
- Errors are always Error objects
Installation
$ npm install betterr
Usage
- Wrap any code that may throw
import { betterr } from 'betterr'; // const { betterr } = require('betterr');
const { data: user, err } = await betterr(() => getUserWithId(1));
// user: User | null, err: Error | null
- Now either
-
Avoid handling the error, and use optional chaining
const maybeName = user?.name; // maybeName: string | undefined
-
Handle the error (interrupting the control flow), after which optional chaining is not needed
if (err) return; // user: User (after error handled) const name = user.name; // name: string
Explanation
betterr
/ betterSync
execute a callback and return an object with data
(callback return value) and err
(error during execution), one of which will be null depending on the success of the callback.
-
betterr
can be used with both asynchronous and synchronous callbacks. -
betterrSync
can only be used with synchronous callbacks, but avoids wrapping the data in a promise so thatawait
is not necessary.
TypeScript
Both betterr
and betterrSync
are generic.
- The callback return type must be assignable to the first generic parameter (for
data
). It defaults to the callback return type. - The second generic parameter (for
err
) must extend theError
object. It defaults toError
.
/**
* const betterrSync: <TData, TError extends Error = Error>
* (callback: () => TData) =>
* | { data: TData; err: null }
* | { data: null; err: TError }
*/
const { data, err } = betterrSync<User, RangeError>(() => ({ id: 1 }));
// data: User | null, err: RangeError | null