errgo-ts
Version:
A lightweight error handling library inspired by Go and Rust.
183 lines (134 loc) • 4.9 kB
Markdown
[](https://www.npmjs.org/package/errgo-ts)




[](https://github.com/austin-weeks/errgo-ts/actions/workflows/Tests.yaml)
_Forgo your error woes with ErrGo's ergonomic error handling!_
# ErrGo
A lightweight, drop-in TypeScript library for ergonomic error handling, inspired by Go and Rust.
ErrGo works harmoniously with TypeScript's built-in error handling, addressing its pain points and rough edges. It does _not_ try to ban exceptions or try/catch blocks from your codebase.
## Installation
```shell
pnpm add errgo-ts
npm install errgo-ts
yarn add errgo-ts
```
## Features
### `tryCatch` - Errors-as-values try/catch wrapper
Execute functions safely and get structured results instead of throwing errors. Works seamlessly with both synchronous and asynchronous functions.
**Sync Usage:**
```typescript
import { tryCatch } from "errgo-ts";
const result = tryCatch(() => fs.readFileSync("file.txt", "utf-8"));
if (result.err) {
console.error("Failed to read file:", result.err);
return "";
}
return result.val;
```
**Async Usage:**
```typescript
import { tryCatch } from "errgo-ts";
const result = await tryCatch(async () => {
const resp = await fetch("/api/data");
const json = await resp.json();
return processData(json);
});
if (result.err) {
throw new Error("Could not fetch data", { cause: result.err });
}
return result.val;
```
### `propagateError` - Declarative error propagation
Add context to errors without verbose try/catch blocks while preserving the original cause chain.
_Instead of this verbose pattern..._
```typescript
let data;
try {
data = getData();
} catch (e) {
throw new Error("Failed to get data", { cause: e });
}
```
_...use `propagateError`!_
```typescript
import { propagateError } from "errgo-ts";
const data = propagateError("Failed to get data", () => getData());
```
### `ensureError` - No more unknown catches
Guarantee you're working with Error instances, even when catching unknown values. Handles all the weird ways JavaScript allows throwing non-Error objects.
```typescript
import { ensureError } from "errgo-ts";
try {
throw "i'm throwing a string!";
} catch (e: unknown) {
const error = ensureError(e); // Always returns an Error instance
console.error(error.message); // "Non-Error object was thrown: i'm throwing a string!"
}
```
### `Result` Type
A discriminated union representing success or failure with full type safety:
```typescript
type Result<T, E = Error> =
| { val: T; err?: undefined }
| { err: E; val?: undefined };
const success: Result = { val: 2 };
const failure: Result = { err: new Error() };
```
## More Information
### Error Cause Chain Preservation
Both `propagateError` and `ensureError` preserve the original error in the cause chain, making debugging much easier:
```typescript
try {
const data = propagateError("Failed to get data", () => {
throw new Error("Network timeout");
});
} catch (error) {
console.log(error.message); // "Failed to get data"
console.log(error.cause?.message); // "Network timeout"
}
```
### JavaScript's Error Edge Cases
ErrGo's `tryCatch` handles edge cases that are not always obvious with traditional try/catch:
```typescript
// Non-Error throws are safely converted
const result = tryCatch(() => {
throw null;
throw undefined;
throw "string error";
throw { custom: "error object" };
});
if (result.err) {
console.log(result.err instanceof Error); // true
}
// Promise rejections are properly coverted to Error instances
const result = await tryCatch(() => Promise.reject("async error"));
if (result.err) {
console.log(result.err instanceof Error); // true
}
```
### Type-Safe Error Handling
The `Result` type leverages TypeScript's type system to force the user to check for an error before using the returned value:
```typescript
// { val: number | undefined, err: Error | undefined }
const result = tryCatch(() => 2);
if (result.err) {
// TypeScript knows val is undefined and err is an Error
// { val: undefined, err: Error }
console.error(result.err.message);
} else {
// TypeScript knows err is undefined and val is a number
// { val: number, err: undefined }
console.log(result.val + 3);
}
```
### Export Options
ErrGo provides flexible import options:
```typescript
// Named imports (recommended)
import { tryCatch, propagateError, ensureError } from "errgo-ts";
// Default import
import errgo from "errgo-ts";
const result = errgo.tryCatch(() => foo());
```