Skip to content

Repository files navigation

@deessejs/errors

Lightweight, type-safe error handling for TypeScript — Python-style. Function-based API, exception chaining, hierarchical inheritance, and rich error semantics. ESM-only, designed for first-class interoperability with @deessejs/fp's Result and Try.

LicenseCIStarsnpm

Documentation

Sibling projects:@deessejs/fp provides Result and Try types that integrate natively with @deessejs/errors error factories. Install them together to get a complete error-handling story without glue code.


What is included

LayerWhat you getWhy it matters
error()Define error factories with name, message templates, fields, and inheritance.Python-style error definitions without classes.
.from() chainingCause chain via .from() + causes() traversal.Link errors together while preserving the full chain context.
Single or multiple inheritanceinherits: accepts a factory or an array.Organize error hierarchies that match your domain.
is() type checkingRuntime and type-safe classifier with inheritance support.Discriminate errors without brittle instanceof.
.addNote()Attach runtime context to error instances.Python 3.11-style notes (PEP 678) for trail-of-breadcrumbs debugging.
Message templates{field} placeholders with :upper, :lower, :json modifiers.Readable messages composed from structured fields at construction time.
Standard Schema fieldsAccepts Zod / Valibot / ArkType schemas.Validated structured data on every error instance, no hand-rolled guards.
raise()Idiomatic throw helper.Type-narrowed (never) raise(err) for control-flow readability.
@deessejs/fp integrationResult/Try accept ErrorInstance directly.Type-safe error pipelines end-to-end, no string-error footguns.

Why this library

  • Simple by default. No class hierarchies to manage, no decorators under reflection. Just factory functions and chained calls.
  • ESM-only. Modern packaging, no CJS shim, no module/main duplication.
  • Minimal runtime. The only runtime dependency is @standard-schema/spec.
  • TypeScript first-class. Strict types, no any leakages, full inference. JSDoc on every public symbol.
  • Real testing. Vitest with type-level and runtime tests, including cause-chain traversal.

Quick start

Prerequisites

  • Node.js 22.x for consumers (the package emits ESM)
  • pnpm 10+ for development (corepack enable if not installed)
  • TypeScript 5.x for consumers (dist/*.d.ts is published)

Install

npm install @deessejs/errors

@deessejs/fp is optional - install it if you want to compose Result/Try types around ErrorInstance.

Usage

import{error,raise,is,causes}from'@deessejs/errors';// Define an error factory with a templated messageconstValidationError=error({name: 'ValidationError',message: 'Field "{field}" is invalid: {reason}',});// Construct a typed errorconsterr=ValidationError({field: 'email',reason: 'invalid format'});// err.message === 'Field "email" is invalid: invalid format'// Chain a causeconstcause=error({name: 'NetworkError'})();err.from(cause);// Throw itraise(err);// Later, type-check and walk the chainis(err,ValidationError);// truecauses(err);// [cause]

Engine compatibility

RuntimeMinimum version
Node.js22.0.0
pnpm10 (for development)
TypeScript5.x

ESM-only. Consumers using a CJS resolver need to use dynamic import() or migrate to ESM.

Available commands

Package: @deessejs/errors

CommandWhat it does
pnpm --filter @deessejs/errors buildBuild dist/ (tsc -p tsconfig.build.json)
pnpm --filter @deessejs/errors testRun vitest in watch mode
pnpm --filter @deessejs/errors test:runRun vitest once
pnpm --filter @deessejs/errors type-checktsc --noEmit
pnpm --filter @deessejs/errors lintRun ESLint

Root (monorepo)

CommandWhat it does
pnpm buildBuild via Turborepo
pnpm testRun all tests
pnpm lintLint every workspace
pnpm type-checkType-check every workspace
pnpm formatFormat with Prettier

App: web (documentation site)

CommandWhat it does
pnpm --filter web devStart the docs site in dev mode
pnpm --filter web buildBuild the docs site for production

Compatibility

Runtime dependency

PackageRequiredNotes
@standard-schema/specYes, >=1.0.0The interface used by fields. Schema implementations (Zod, Valibot, ArkType) are passed by the caller.

Peer dependencies

PackageRequiredNotes
@deessejs/fpOptional, peer >=1.0.0Recommended if you want Result/Try types around ErrorInstance. Not required for using @deessejs/errors alone.

Engines

FieldValue
engines.node>=22.14.0
packageManagerpnpm@10.34.5

Project structure

.
├── packages/
│ └── errors/ # The library — @deessejs/errors on npm
│ ├── src/ # Source code (ESM)
│ ├── tests/ # Vitest suites
│ ├── dist/ # Build output (gitignored)
│ └── tsconfig.build.json
├── apps/
│ └── web/ # Documentation site (Next.js + Fumadocs)
├── docs/
│ ├── internal/ # Engineering plans, runbooks
│ │ ├── product/
│ │ └── versions/
│ └── engineering/
├── pnpm-workspace.yaml
├── turbo.json # Turborepo pipelines
├── .changeset/ # Changesets for versioning
└── README.md

Publishing

Releases are fully automated via Changesets + npm Trusted Publishing (OIDC). No long-lived NPM_TOKEN is required.

WhatHow
Bump versionAdd a .changeset/<topic>.md file with semver and description on a PR to staging
Open the release PRCherry-pick selected commits from staging into release/vX.Y.Z and PR to main
PublishMerge to main - release.yml detects changesets and publishes via Trusted Publishing to npm with provenance attestation
HotfixBranch from main as release/hotfix-<slug>, open PR directly to main with [hotfix] label. Same workflow fires.
RollbackUse pnpm changeset version then revert the merge. npm deprecations: pnpm npm deprecate @deessejs/errors@<rev> '<msg>'

For the full release runbook, see docs/internal/engineering/process/releasing-a-new-version.md.

Architecture notes

  • ESM-only. The package exports ES modules. Consumers using legacy CJS resolvers must use dynamic import().
  • Strict types.error() returns a typed factory; is() narrows. No any leakages.
  • Composition over inheritance. All error primitives compose via instance methods (.from(), .addNote(), inherits). No class hierarchy on the consumer side.
  • Zero decorators. Pure factory functions. The library is straightforward to read in DevTools and node --prof.
  • Smoke-tested before publish. The release workflow imports the built artifact and verifies key exports are present. A broken build fails the publish step before reaching npm.
  • Symmetric interop with @deessejs/fp.Result constructors accept ErrorInstance so you never have to coerce a typed error to a string.

Contributing

Open an issue to discuss larger changes. For typos, broken links, and small fixes, PRs are welcome.

Before submitting a PR:

  1. Run pnpm --filter @deessejs/errors test:run and pnpm --filter @deessejs/errors lint.
  2. Add a .changeset/<topic>.md if the change is user-facing (patch / minor / major).
  3. Update docs/internal/product/README.md if the API surface changes.

Acknowledgements

The README layout and monorepo tooling for this project are based on the deessejs/package-template. The shipped README borrows its structure from the deessejs/fp README, adapted for the @deessejs/errors API surface.

License

MIT. See the LICENSE file for details.

Support

About

A TypeScript error handling library with exception chaining, hierarchical inheritance, and rich error semantics

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages