DeesseJS Errors

Getting Started

Get started with @deessejs/errors, a TypeScript error handling library with exception chaining and hierarchical inheritance.

@deessejs/errors is a TypeScript library that reimagines error handling in JavaScript. Inspired by Python's exception system, it provides exception chaining, hierarchical inheritance, and rich error semantics through a function-based API.

This library is particularly useful when you need to:

  • Preserve the full context of errors across async boundaries and service calls
  • Organize errors in meaningful hierarchies that reflect your domain
  • Attach structured data and metadata to errors for better debugging

Quick Start

The quickest way to understand how @deessejs/errors works is to see it in action. Here's a basic example that demonstrates creating typed errors and chaining them together.

index.ts
import { error, raise } from '@deessejs/errors';

// Define your error types
const ValidationError = error({
  name: 'ValidationError',
  message: 'Validation failed',
});

// Use the factory to create error instances
const validationErr = ValidationError({});
console.log(validationErr.message); // "Validation failed"

For catching and handling errors, you can use the standard try/catch syntax or the library's raise() function:

handling.ts
try {
  raise(ValidationError({}));
} catch (err) {
  console.log(err.name); // "ValidationError"
  console.log(err instanceof Error); // true
}

Key Features

Exception Chaining

When an error occurs as a result of another error, you can preserve that relationship using the .from() method. This creates a chain that maintains the full history of what went wrong.

chaining.ts
const validationErr = ValidationError({});
const appErr = error({ name: 'AppError' })();

// Chain the validation error as the cause
appErr.from(validationErr);

console.log(appErr.cause === validationErr); // true
console.log(appErr.causes.length); // 1

Hierarchical Inheritance

Errors can inherit from other errors, creating hierarchies that are useful for organization and type checking. A child error can check against its parent types.

inheritance.ts
import { error, is } from '@deessejs/errors';

const AppError = error({ name: 'AppError' });
const ValidationError = error({
  name: 'ValidationError',
  inherits: AppError,
});

const err = ValidationError({});

// Check the error type
console.log(is(err, ValidationError)); // true
console.log(is(err, AppError)); // true (through inheritance)

Message Templates

You can define errors with message templates that include field placeholders. These are replaced at runtime with the data you provide.

templates.ts
const UserError = error<{ userId: string; reason: string }>({
  name: 'UserError',
  message: 'User "{userId}" failed: {reason}',
});

const err = UserError({ userId: 'usr_123', reason: 'not found' });
console.log(err.message); // "User "usr_123" failed: not found"

See Also

On this page