Loading...
Loading...
[Pragmatic DDD Architecture] Guide for creating strictly typed Domain validation and infrastructure errors. Use when handling or creating new errors to ensure they conform to the Railway-oriented programming model (neverthrow Result), TypeScript error branding, and constructor parameter constraints. Covers co-location rules vs. shared domain error usage.
npx skill4agent add leif-sync/pragmatic-ddd errorsneverthrowResult<T, E>enumErrordeclare private readonly [unique]: neverunique symbolinstanceofassertNeverErrorparams: { ... }private readonly.get...()publicsuper(...).toBranded().getEncoded()InvalidEmailErrorFolderAlreadyExistsErrorUserNotFoundErrorparams: { ... }import { FolderName } from "../value-objects/folderName";
declare const unique: unique symbol;
export class FolderAlreadyExistsError extends Error {
// BRANDING: This ensures TypeScript treats this type strictly.
declare private readonly [unique]: never;
// MUST store the actual Value Object privately
private readonly folderName: FolderName;
constructor(params: { folderName: FolderName }) {
// MUST extract the primitive value via `.toBranded()` for message formatting
super(`Folder with name "${params.folderName.toBranded()}" already exists.`);
this.folderName = params.folderName;
}
// MUST return the Value Object
getFolderName(): FolderName {
return this.folderName;
}
}ErrorErrordeclare const unique: unique symbol;
export class RepositoryError extends Error {
declare private readonly [unique]: never;
constructor(error: Error) {
const { message, ...rest } = error;
super(message, rest);
}
}Result.err()throw// ✅ RECOMMENDED - Railway flow
if (folders.length > 0) {
return err(new FolderAlreadyExistsError({ folderName }));
}
// ❌ MUST NOT - Never throw domain validation exceptions directly
if (folders.length > 0) {
throw new FolderAlreadyExists({ folderName });
}.agents/skills/errors/references/