Option<T> |
non-Option (T | undefined ) |
|
---|---|---|
accessing property | userOption.map(user => user.age) |
userNullish?.age |
calling a method | userOption.map(user => user.fn()) |
userNullish?.fn() |
providing fallback | ageOption.getOrElse(0) |
ageNullish ?? 0 |
filter | ageOption.filter(checkIsOddNumber) |
ageNullish !== undefined && checkIsOddNumber(ageNullish) ? ageNullish : undefined |
map | ageOption.map(add1) |
ageNullish !== undefined ? add1(ageNullish) : undefined |
flat map / chain | ageOption.flatMap(add1) |
ageNullish !== undefined ? add1(ageNullish) : undefined |
check for existence with predicate | ageOption.exists(checkIsOddNumber) |
ageNullish !== undefined ? checkIsOddNumber(ageNullish) : false |
check for existence with method | nameOption.exists(name => name.startsWith('bob')) |
nameNullish?.startsWith('bob') ?? false |
nesting | Option<Option<T>> |
impossible |
sequencing | sequence(fa, fb) |
fa !== undefined ? fb !== undefined ? [fa, fb] : undefined : undefined |
mapping multiple | sequence(fa, fb).map(add) |
fa !== undefined ? fb !== undefined ? add([fa, fb]) : undefined : undefined |
const age1 = userOption
.flatMap(user => user.age)
.map(plus1)
.filter(checkIsOddNumber)
.getOrElse(0);
const age2 =
(user?.age !== undefined
? (() => {
const agePlus1 = plus1(user.age);
return checkIsOddNumber(agePlus1) ? agePlus1 : undefined;
})()
: undefined) ?? 0;
Yeah sorry, I actually skipped the filter 😓 Negative values are truthy. There would need to be additional ternary and second call to plus1 or a partial result variable. My snippet was closer to this one, assuming you can pass undefined to plus1.
This one should make more sense. Default parameters and destructuring are probably idiomatic JS.
One could argue that this doesn't require familiarity with any library.
I do believe that
Option
is very useful, especially because of how easy it is to move betweenOption
andEither
.I just wanted to say that I find the second example (with IIFE) a bit artificial.