[Typescript] Restrict available operations on values using value objects
Value Objects are another pattern in Domain-driven Design that provide more structure around what you can and cannot do with a type.
In TypeScript we create Value Objects with classes that will define what operations can be performed to the value on the class itself. In this lesson we'll explore how to create a Value Object for our Money
type.
declare const __brand_type__: unique symbol
type Branded<BrandType, BrandName> = BrandType & {
readonly [__brand_type__]: BrandName
}
type Currency = "USD" | "EUR"
type Money = Branded<number, "MONEY">
class Money {
constructor(
private amount: Money,
private currency: Currency
) {}
add(another: Money) {
if (this.currency != another.currency) {
throw new Error(`Cannot add different currencies`);
}
return new Money(
this.amount + another.amount,
this.currency
);
}
multiply(factor: number) {
return new Money(this.amount * factor, this.currency);
}
}
Due to definitly assign problem for constructor
, you cannot restrict object creation by using constructor
. One way to do it is using static from
method.
- change
constructor
toprivate
- add
static from
method
declare const __brand_type__: unique symbol
type Currency = "USD" | "EUR"
class Money {
private constructor(
private amount: number,
private currency: Currency
) {}
static from(amount: number, currency: Currency) {
if (amount <= 0) {
throw new Error(`Cannot add different currencies`)
}
return new Money(
this.amount + another.amount,
this.currency
)
}
add(another: Money) {
if (this.currency != another.currency) {
throw new Error(`Cannot add different currencies`);
}
return new Money(
this.amount + another.amount,
this.currency
);
}
multiply(factor: number) {
return new Money(this.amount * factor, this.currency);
}
}