Getting started
Try It Live
You can try self-assert
directly in your browser on CodeSandbox.
Installation
sh
npm install self-assert
sh
pnpm add self-assert
sh
yarn add self-assert
Validating Domain Objects with Assertion
The Assertion
class lets you express rules declaratively. You can:
- Define self-contained rules (no parameters)
- Define reusable rules that apply to different values
A typical example:
ts
import { Assertion, Requirements, Ruleset } from "self-assert";
export class Person {
static readonly nameNotBlank = Assertion.requiring(
"name.notBlank",
"Name must not be blank",
Requirements.isNotBlank
);
static readonly agePositive = Assertion.requiring(
"age.positive",
"Age must be positive",
Requirements.isPositive
);
static named(name: string, age: number) {
Ruleset.ensureAll(
this.nameNotBlank.evaluateFor(name),
this.agePositive.evaluateFor(age)
);
return new this(name, age);
}
protected constructor(protected name: string, protected age: number) {}
getName() {
return this.name;
}
getAge() {
return this.age;
}
}
If any rule fails, a RulesBroken
error is thrown with details.
Suggesting Completion with Draft Assistants
FieldDraftAssistant
and SectionDraftAssistant
help you manage incomplete or draft objects, especially useful in UI flows or external interfaces.
ts
function createPersonAssistant() {
const nameAssistant = FieldDraftAssistant.handlingAll(
["name.notBlank"],
(person: Person) => person.getName()
);
const ageAssistant = IntegerDraftAssistant.for(
"age.positive",
(person: Person) => person.getAge()
);
const personAssistant = SectionDraftAssistant.topLevelContainerWith(
[nameAssistant, ageAssistant],
(name, age) => Person.named(name, age),
[]
);
return Object.assign(personAssistant, { nameAssistant, ageAssistant });
}
TIP
Object.assign
lets you expose the inner assistants of a composed one, so you can reuse them without creating a dedicated subclass.
The assistant lets you defer object creation until all validations pass:
ts
const personAssistant = createPersonAssistant();
personAssistant.nameAssistant.setModel(" ");
personAssistant.ageAssistant.setModel(30);
personAssistant.withCreatedModelDo(
() => {
throw new Error("this should not happen");
},
() => console.log("Person not created")
);
console.log(personAssistant.hasBrokenRules());
personAssistant.nameAssistant.setModel("John");
personAssistant.ageAssistant.setModel(50);
personAssistant.withCreatedModelDo(
(person) => console.log(`Person created: ${person.getName()}`),
() => {
throw new Error("this should not happen");
}
);