๐Ÿ“ฆ syhner / betterr

A better way to handle errors. 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.

โ˜… 11 stars โ‘‚ 1 forks ๐Ÿ‘ 11 watching โš–๏ธ MIT License
async-awaiterror-handlingerrorsexceptionspackagepromisetry-catchtypescript
๐Ÿ“ฅ Clone https://github.com/syhner/betterr.git
HTTPS git clone https://github.com/syhner/betterr.git
SSH git clone git@github.com:syhner/betterr.git
CLI gh repo clone syhner/betterr
github-actions[bot] github-actions[bot] Version Packages (#24) 4ec90c6 1 years ago ๐Ÿ“ History
๐Ÿ“‚ main View all commits โ†’
๐Ÿ“ .changeset
๐Ÿ“ .github
๐Ÿ“ patches
๐Ÿ“ src
๐Ÿ“„ .eslintrc.json
๐Ÿ“„ .gitignore
๐Ÿ“„ .npmignore
๐Ÿ“„ .prettierignore
๐Ÿ“„ .prettierrc.json
๐Ÿ“„ CHANGELOG.md
๐Ÿ“„ LICENSE
๐Ÿ“„ package.json
๐Ÿ“„ pnpm-lock.yaml
๐Ÿ“„ README.md
๐Ÿ“„ tsconfig.json
๐Ÿ“„ turbo.json
๐Ÿ“„ vite.config.ts
๐Ÿ“„ README.md

betterr

A better way to handle errors

build status coverage

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 [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 a tuple 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 that await 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 the Error object. It defaults to Error.
/**
 * const betterrSync: <TData, TError extends Error = Error>
 * (callback: () => TData) => [TData, null] | [null, TError]
 */

const [user, err] = betterrSync<User, RangeError>(() => ({ id: 1 }));
// data: User | null, err: RangeError | null