-1

Since I read a few articles on error handling, i still wondering wether throw exception on a validation logic in the value object is the bad way. For instance, I have this class below which is the value object:

export class UserName {
  private readonly value: string;

  constructor(value: string) {
    this.value = this.evaluateName(value);
  }

  private evaluateName(value: string): string {
    value = value.trim();
    if (value === "") {
      throw new UserNameError("username is required!");
    }
    return value;
  }

  static userNameOf(name: string): UserName {
    return new UserName(name);
  }

  public isValidName(): boolean {
    if (!/^[a-zA-Z]+$/.test(this.value)) {
      throw new UserNameError("user name should contain only letter");
    }
    return true;
  }

}

So,What if there best way to to handling error instead of throw error like i did. Thanks :)

Ben Wainwright
  • 4,224
  • 1
  • 18
  • 36
dollars
  • 37
  • 8

1 Answers1

0

One of the benefits of using value objects is that they can enforce their own invariants. It's a good idea to follow the "always valid" principle meaning that entities, aggregate roots and value objects are never in a state that violates their invariants.

As such, there is no problem in throwing exceptions from the value object. In fact, in your example it should be stricter. You can currently create a Username Value Object that would fail the isValidName() test as it is not checked prior to completion of construction.

I'd refactor to this:

export class UserName {
  private readonly value: string;

  constructor(value: string) {
    trimmed: string;
    trimmed = value.trim();
    
    if (trimmed === "") {
       throw new UserNameError("Username is required!.");
    }

    if (!/^[a-zA-Z]+$/.test(trimmed)) {
      throw new UserNameError("user name should contain only letter");
    }    

    this.value = trimmed;
  }

  static userNameOf(name: string): UserName {
    return new UserName(name);
  }
}
Neil W
  • 7,670
  • 3
  • 28
  • 41
  • great! it's seem relevant to me what you. But i think it's not a really best pratice while adding logic to the object construction(unless i'm wrong). What i suggest is to remove validation logic and having something like this ` static userNameOf(name:string):UserName { if(name === "") { throw new UserInputError("username is required!"); } return new UserName(name); }`. – dollars Oct 16 '21 at 17:37
  • There's nothing wrong with validation logic directly in the constructor ... if all validations apply at all times. If, perhaps, there were two different ways of requesting a UserName and they had different validations, then it would make sense to implement those respective validations in the static factory methods for each and then call the single constructor (that doesn't validate) once all params are validated by the static factories. But if there's no special cases, I'd just put it all in the constructor. There's nothing bad practice about that. – Neil W Oct 16 '21 at 18:55