Option — absent values
Absence is everywhere in real code. A user that might not be in the database, a config value that might not be set, a lookup that might come up empty. The usual answer is T | null, and then a null check at every call site — each one a reminder that something might not be there. Option<A> makes the absence part of the type itself, so the check happens once and composes cleanly with everything else.
The problem with null
Section titled “The problem with null”When a function returns User | null, nothing in the type system stops you from accessing .name without checking first. The compiler will warn you in strict mode, but the check lives in your code — and your code alone. Every caller has to remember to do it:
This scales poorly. The more values that might be absent, the more if (x !== null) checks you accumulate, often spread across different files and functions.
The Option approach
Section titled “The Option approach”With Option, the absence is encoded in the type itself. You can’t accidentally skip the check — the operations that work on an Option handle both cases for you:
The map step only executes if the value is Some. If getUser returns None, the map is skipped and None flows through to getOrElse, which then returns the fallback. You never wrote a conditional — the type enforced the handling.
Creating Options
Section titled “Creating Options”fromNullable is the most common entry point when working with existing APIs that return null or undefined:
Transforming values with map
Section titled “Transforming values with map”map transforms the value inside a Some, leaving None untouched:
You can chain multiple map calls — each one only runs if the previous step produced a Some:
Chaining with chain
Section titled “Chaining with chain”When a transformation itself might produce an absent value, use chain instead of map. It prevents nesting Option<Option<A>>:
Think of it as: map is for transformations that always succeed; chain is for transformations that might not.
Filtering
Section titled “Filtering”filter turns a Some into None if the value doesn’t satisfy a predicate:
This is useful for narrowing values within a pipeline without breaking out of the Option context.
Extracting the value
Section titled “Extracting the value”At the edge of your pipeline, you need to get a plain value back. There are a few ways:
getOrElse — provide a fallback value:
match — handle each case explicitly, producing a value from either branch:
fold — same as match but with positional arguments (none handler first, some handler second):
toNullable / toUndefined — escape hatch back to null/undefined when interoperating with APIs that expect them:
Recovering from None
Section titled “Recovering from None”recover provides a fallback Option when the current one is None. Unlike getOrElse, the fallback is itself an Option — useful when the fallback operation might also fail:
Converting to and from Result
Section titled “Converting to and from Result”Option and Result are closely related — the difference is whether the absent case carries an error message. You can convert between them:
When to use Option vs null
Section titled “When to use Option vs null”Use Option when:
- You want absence to be visible in the type signature and composable through pipelines
- Multiple operations in sequence might each fail to find a value
- You want to use
map,chain, andfilterwithout manual null checks at every step
Keep returning null or undefined when:
- You’re writing a small utility that only you consume and null is simpler
- You’re interfacing with code that expects null (use
toNullableat the boundary)