Tagged errors are native Error instances extended with a _tag discriminant. They let you build discriminated unions of errors that TypeScript can check exhaustively — and that work with real stack traces, console.log, and error monitoring services.
Defining errors
chas.defineErrs() takes an object where each key becomes a _tag and the value is a factory function that returns the error’s extra data:
Each factory produces a real Error instance with:
- A
_tag field matching the key name
- A
name field set to the tag
- A full stack trace
- All the data properties you returned from the factory
Creating errors
Call the factory directly, or use the .err() helper to wrap it in a Result:
Inferring types
Using errors in function signatures
Exhaustive matching
chas.matchErr() requires a handler for every variant. TypeScript will error if you miss one:
Partial matching
chas.matchErrPartial() lets you handle only the variants you care about. The _ handler catches everything else and receives the remaining union type:
Catching a specific tag mid-chain
.catchTag() handles a single variant inline, removing it from the error union. The remaining chain has a narrower error type:
You can also match by tag string instead of factory:
Tapping a tag without catching
.tapTag() runs a side effect on a specific variant but leaves the result unchanged:
Guard integration
Use is.tagged() to check an unknown value against a tagged error factory:
Each error factory has a .is(value) method as a convenience type guard. You can also use is.tagged(AppError.NotFound) from ts-chas/guard for the same effect.
Error wrapping with cause
If your factory data includes a cause property that is an Error, it is set as the native Error.cause, creating a proper error chain: