Tagged errors
Define discriminated Error subclasses with typed properties, guards, JSON output, causes, and generator support.
TaggedError creates real Error subclasses with a literal _tag and typed properties.
Define an error
import { TaggedError } from "better-result";
class UserNotFound extends TaggedError("UserNotFound")<{
userId: string;
message: string;
}> {}
const error = new UserNotFound({
userId: "usr_123",
message: "User usr_123 was not found",
});
The class has normal Error behavior plus:
name === "UserNotFound";_tag === "UserNotFound"as a string literal;- readonly
userIdand other declared properties; toJSON();- exhaustive
.match()by_tag; UserNotFound.is(value);- iterator support for
yield*.
Match an error union
const message = error.match({
UserNotFound: (error) => `No user ${error.userId}`,
PermissionDenied: (error) => `Missing permission ${error.permission}`,
});
The handler map must cover every variant in the receiver’s error union. Each handler receives its concrete error subtype. If the selected handler throws, .match() throws Panic with that exception as its cause. Use the standalone matchError function for structurally tagged errors or data-last matching.
match is reserved for this method. A TaggedError payload property or incompatible subclass member named match is rejected by TypeScript.
Add a computed message
class RequestFailed extends TaggedError("RequestFailed")<{
url: string;
status: number;
message: string;
}> {
constructor(args: { url: string; status: number }) {
super({
...args,
message: `Request to ${args.url} failed with ${args.status}`,
});
}
}
Preserve a cause
Declare cause in the property type and pass it to super:
class ParseFailed extends TaggedError("ParseFailed")<{
input: string;
cause: unknown;
message: string;
}> {}
new ParseFailed({ input, cause, message: "Could not parse input" });
Native Error.cause is populated. toJSON() serializes an Error cause to its name, message, and stack.
Guards
if (UserNotFound.is(value)) {
value.userId;
}
if (TaggedError.is(value)) {
value._tag;
value.toJSON();
}
if (isTaggedError(value)) {
value._tag;
}
TaggedError.is and isTaggedError detect any better-result tagged error. A concrete class’s .is guard detects that class.
Yield directly
const result = Result.gen(function* () {
if (!user) {
yield* new UserNotFound({ userId, message: "User not found" });
}
return Result.ok(user);
});
Public helper types
TaggedErrorClass<Tag>describes the factory’s generic class.TaggedErrorInstance<Tag, Props>describes an instance structurally.AnyTaggedErrordescribes any tagged error withtoJSON().