@hmpsn/ts-ddd
v1.0.0
Published
Base classes for implementing Domain-Driven Design (DDD) applications in TypeScript
Maintainers
Readme
ts-ddd
Base classes for implementing Domain-Driven Design (DDD) applications in TypeScript.
Installation
npm install ts-dddFeatures
This package provides the following DDD building blocks:
- Entity: Base class for entities with unique identifiers
- ValueObject: Base class for immutable value objects
- AggregateRoot: Base class for aggregate roots with domain event support
- DomainEvent: Base class for domain events
- Repository: Interface for repository pattern
- UniqueEntityID: Utility class for generating unique identifiers
Usage
Entity
Entities are objects that have a unique identity that runs through time and different representations.
import { Entity } from 'ts-ddd';
interface UserProps {
name: string;
email: string;
}
class User extends Entity<string> {
get name(): string {
return this.props.name;
}
get email(): string {
return this.props.email;
}
public updateEmail(newEmail: string): void {
this.props.email = newEmail;
}
}
// Create a new user
const user = new User('user-123', { name: 'John Doe', email: '[email protected]' });
console.log(user.id); // 'user-123'
console.log(user.name); // 'John Doe'ValueObject
Value Objects are immutable objects that are defined by their attributes rather than a unique identity.
import { ValueObject } from 'ts-ddd';
interface AddressProps {
street: string;
city: string;
zipCode: string;
}
class Address extends ValueObject<AddressProps> {
get street(): string {
return this.props.street;
}
get city(): string {
return this.props.city;
}
get zipCode(): string {
return this.props.zipCode;
}
}
// Create addresses
const address1 = new Address({ street: '123 Main St', city: 'Springfield', zipCode: '12345' });
const address2 = new Address({ street: '123 Main St', city: 'Springfield', zipCode: '12345' });
// Value objects with same properties are equal
console.log(address1.equals(address2)); // trueAggregateRoot
An Aggregate Root is an entity that is the root of an aggregate, which is a cluster of domain objects that can be treated as a single unit.
import { AggregateRoot, DomainEvent, UniqueEntityID } from 'ts-ddd';
class OrderPlacedEvent extends DomainEvent {
constructor(aggregateId: UniqueEntityID, public readonly total: number) {
super(aggregateId);
}
}
interface OrderProps {
total: number;
status: string;
}
class Order extends AggregateRoot<string> {
get total(): number {
return this.props.total;
}
get status(): string {
return this.props.status;
}
public placeOrder(): void {
this.props.status = 'placed';
const event = new OrderPlacedEvent(new UniqueEntityID(this.id), this.total);
this.addDomainEvent(event);
}
}
// Create and place an order
const order = new Order({ total: 100, status: 'pending' }, 'order-123');
order.placeOrder();
// Access domain events
console.log(order.domainEvents.length); // 1
console.log(order.domainEvents[0] instanceof OrderPlacedEvent); // true
// Clear events after dispatching
order.clearEvents();Repository Interface
The Repository interface provides a contract for data access objects.
import { IRepository } from 'ts-ddd';
class UserRepository implements IRepository<User> {
async findById(id: string): Promise<User | null> {
// Implementation
return null;
}
async save(entity: User): Promise<void> {
// Implementation
}
async delete(entity: User): Promise<void> {
// Implementation
}
}Development
# Install dependencies
npm install
# Build the package
npm run build
# Run tests
npm test
# Lint code
npm run lint
# Format code
npm run formatContributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT
