Value objects that can't be invalid
A value object wraps a primitive (or a few) in a type that cannot exist in an invalid state. A FlightNumberVo is a string that is guaranteed non-blank, because the only way to make one is through a factory that validates. Contrast the TS habit of passing a bare string everywhere and validating at each use site: the VO validates once, at construction, and every downstream consumer trusts it.
The mechanism is a private constructor plus a static Create factory that returns Result<T>. You can't call new FlightNumberVo(...) from outside; you call Create, which either hands you a valid VO or a failure. An invalid VO is literally unconstructable. Anti-pattern #25 is exactly this: no public constructors on domain types, use the Create factory.
Two base classes carry the equality plumbing so you never write it. SingleValueObject<TSelf, TValue> is for a one-primitive wrapper: it gives you .Value, value equality, and ToString() for free. ValueObject<T> is for multi-field VOs: you override GetEqualityComponents() and yield return each field, and equality falls out. DisruptionDelayVo from the last lesson uses the multi-field base.
Try it yourself
Write a value object from the pattern
Produce the pattern yourself, because you'll write these constantly.
Tick every step to confirm you did it.
Why the constructor is private
Why does a Fusion value object make its constructor private?