0

I can not find any clear example of how to implement Aggregate Root (DDD) with properly encapsulated its internal state with help of JavaScript/TypeScript. Below I suggest an idea on how to implement it. Maybe someone has ideas on how to improve this solution:

import cloneDeep from 'clone-deep';
import { deepFreeze } from '../utils'; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

export class AggregateRoot<TEntityProps> {
  // TODO EntityId
  
  protected readonly props: TEntityProps

  constructor(props: TEntityProps) {
    /** Encapsulate aggregate's state from the outside world */
    this.props = cloneDeep<TEntityProps>(props)
  }
  
  /** Extract the state from an aggregate. 
   * 
   * Aggregate becomes unchangeable (read-only) after calling the flush method.
   * */
  public flush(): TEntityProps {
    return deepFreeze(this.props)
  }
}

// Usage
export class User extends AggregateRoot<UserProps> {
  constructor(props: UserProps) {
    super(props)
    
    // props validation here

  }

  get firstName() {
    return this.props.firstName
  }

  get lastName() {
    return this.props.lastName
  }

  get updatedAt() {
    return this.props.updatedAt
  }
}

1 Answers1

0

Another variant is to rewrite this method:

  public flush(): TEntityProps {
    return deepFreeze(this.props)
  }

with

  public snapshot(): TEntityProps {
    return cloneDeep(this.props)
  }

But we need to know that in this case, we increase memory consumption twice. So probably, it is suitable for small aggregates, I think.