Optional — nullable paths
If you haven’t read the Lens guide first, start there. It covers why mutating
objects directly causes problems and why producing new copies is the right approach. Optional
builds on that same idea — the difference is that the path through the data might not reach
anything.
The gap in TypeScript’s optional chaining
Section titled “The gap in TypeScript’s optional chaining”TypeScript’s ?. operator lets you safely read through a path that might not exist:
But ?. is read-only. The moment you want to update something at the end of that path,
it stops working. There is no ?.= operator. You are back to writing spreads with conditionals:
Optional<S, A> closes that gap. It is a path through your data that accepts the path might
not reach anything. Reads return Option<A> instead of A. Writes and modifications are
no-ops when the path finds nothing — no conditional required.
The Optional approach
Section titled “The Optional approach”No conditional. The absent case is handled by the Optional itself.
Defining an optional path
Section titled “Defining an optional path”Optional.prop points at an optional field — one declared with ? in its type. Required
fields belong to Lens.prop; Optional.prop only accepts keys where the value might be
undefined:
Optional.index points at an element in an array by position:
Out-of-bounds reads return None. Out-of-bounds writes leave the array unchanged.
Optional.make constructs a custom optional from an explicit getter and setter:
Reading
Section titled “Reading”Optional.get returns Option<A> — Some when the value is there, None when it isn’t:
Extracting a plain value from the result:
Writing
Section titled “Writing”Optional.set always produces a new object — it never mutates. For optional properties, it
inserts the value whether or not the field was there before. For array indices, it is a no-op
when the index is out of bounds:
Optional.modify applies a function to the value if it is present, and returns the structure
unchanged if it is not:
Composing paths
Section titled “Composing paths”Optional.andThen extends a path by another optional step. If either step finds nothing, the
whole path returns None for reads and does nothing for writes:
When the next step is a required field once the optional part resolves, use andThenLens to
continue with a Lens rather than converting it to an Optional manually:
Starting from a Lens
Section titled “Starting from a Lens”A path often begins through required fields and then reaches an optional one. Convert the Lens
to an Optional with Lens.toOptional and continue from there:
Lens vs Optional — when to use which
Section titled “Lens vs Optional — when to use which”| Situation | Use |
|---|---|
| Required field, always present | Lens.prop |
Optional field (field?: T) | Optional.prop |
| Array element by index | Optional.index |
| Path that starts required and becomes optional | Lens.andThenOptional or Lens.toOptional |