Use when: (1) building domain entities with validation, (2) creating value objects, (3) defining repository interfaces, (4) implementing domain services, (5) questions about DDD patterns or business logic encapsulation.
Create domain models in pure TypeScript with zero external dependencies.
The domain layer contains pure business logic only:
src/domain/
├── entities/ # Aggregate roots and entities
│ ├── Order.ts
│ └── Order.spec.ts
├── value-objects/ # Immutable value types
│ ├── Money.ts
│ └── Email.ts
├── services/ # Stateless domain logic
│ └── PricingService.ts
└── interfaces/ # Repository ports (interfaces only)
└── OrderRepository.ts
export class Order {
private constructor(private props: OrderProps) {
// Validate invariants here
}
static create(input: CreateOrderInput): Order {
/* validate + new */
}
static reconstitute(props: OrderProps): Order {
/* from persistence */
}
// Getters + behavior methods that enforce rules
}
export class Money {
private constructor(
public readonly amount: number,
public readonly currency: string
) {}
static of(amount: number, currency: string): Money {
if (amount < 0) throw new Error('Amount cannot be negative');
return new Money(amount, currency);
}
add(other: Money): Money {
if (this.currency !== other.currency) throw new Error('Currency mismatch');
return Money.of(this.amount + other.amount, this.currency);
}
equals(other: Money): boolean {
return this.amount === other.amount && this.currency === other.currency;
}
}
// Domain layer - interface only
export interface OrderRepository {
findById(id: string): Promise<Order | null>;
save(order: Order): Promise<void>;
}
// Stateless, operates on multiple entities/value objects
export class PricingService {
calculateTotal(items: LineItem[], discounts: Discount[]): Money {
// Complex calculation logic here
}
}
| Anti-Pattern | Instead |
|---|---|
import { D1Database } in domain | Define interface in domain, implement in infrastructure |
async in entity methods | Keep entities synchronous; async belongs in repositories |
| Exposing setters | Provide behavior methods: order.addItem() not order.items = [] |
| Validation in application layer | Validate in entity/value object constructors |
| Anemic domain model | Put behavior with the data it operates on |