Options are a powerful functional programming construct. They are commonly one of the first constructs mentioned when learning functional programming. One nice way to think of them is as the programmer’s version of Schrodinger’s cat. There’s a box, and inside the box, there may be a value. Or maybe there isn’t. In either case, it’s impossible to know until the box is opened. To bring the Option object to JavaScript and TypeScript, I wrote and published to NPM called . a fully typed, zero-dependency implementation of the functional programming Option object excoptional The README also reviews Options and their capabilities and contains more information on various methods and capabilities. Take a look if you’re interested in learning more after reading this piece. More formally, Options are an abstraction that works well with functions that may or may not return a value. Options often obviate the need for and checks and provide mechanisms to safely and declaratively transform the value they may (or may not) contain. null undefined Using Options Options take care of the repetitive and checks that might otherwise be needed when working with values returned by functions that may or may not have a value. null undefined Here’s a quick example with two versions of uppercasing function. One takes a and returns either a or . string string undefined The other takes an and returns an . Note the uniformity of the return type compared to in the first example. Option<string> Option<string> string | undefiend const { Some, None } = require('excoptional'); // Without Options const uppercaseStr = (value) => { if (value !== undefined) { return value.toUpperCase(); } return undefined; } const valOne = uppercaseStr("hello world"); // => string const valTwo = uppercaseStr(undefined); // => undefined // With Options const valThree = Some("hello world") // An option containing "hello world" .map(str => str.toUpperCase()); // => Option<string> const valFour = None() // An option with no underlying value .map(str => str.toUpperCase()); // => Option<string> In the first example, the argument is checked to make sure it’s not . undefined TypeScript’s strict mode helps in these circumstances, but only in validating that when calling the function, a value is always passed in (instead of ). The function can still return and callers of will have to check the return value is again not before passing the result to the next function (or implement these undefined checks in every function). string undefined undefined uppercaseStrOne undefined In the second example, we call the method on the Option passing in a function that transforms the underlying value (by uppercasing it). No check is needed in the function passed to . map undefined map This works regardless if the Option contains an underlying value or not like with valFour The result remains an allowing for it to be continuously chained with additional calls that further transform the underlying value. No more or checks needed. Since the type remains an , the context that there may not be a value here is maintained. Option<string> map undefined null Option<string> Options provide the ability to remove errors (like the one below) by wrapping values that may be undefined in an . Option Uncaught TypeError: Cannot read property 'foo' of undefined at myIncrediblyImportantFunction (index.js:8) Constructing Instances of Options Using Options necessitates constructing instances. The example above uses which expose functions and which, when invoke return Options. excoptional Some None takes one argument and is used to create an instance of an Option with that argument as the underlying value. is used when there is no underlying value and so takes no arguments. Some() None() Depending on the library, creating instances may be slightly different but they all have similar semantics. Working with Options Working with functions that return Options instead of direct values (along with and ) leads to a new set of semantics and usage patterns, but Options provide solutions for all scenarios. null undefined Let’s add a validation function before upper casing to check the string length is sufficiently long. From the example above, the method worked for a transformation function that returned a value that is not an . What about transformation functions that themself return an Option? Here’s one. map Option const { Some, None } = require('excoptional'); const getIfValid = (val) => { if (val.length > 2) { return Some(val); } else { return None(); } }; Some("hi") .flatMap(getIfValid) .log(); // Log the result If the provided transformation function returns an , we must use . If were to be used, the result would be a nested Option. To see this, and change to . Try also shortening the string to 2 characters or fewer. Option flatMap map copy the above snippet into runkit flatMap map You can also the module ( ) locally to run examples and test out its various methods. npm install excoptional The TLDR here is: use when the function does not return an map Option use when the function does return an flatMap Option Look out for the And Then… section for an even better solution Getting the Value Eventually, at some point, the underlying value is needed. The goal though is to avoid extracting it for as long as possible and instead pass around the instance. In doing so, the context that there may or may not be a value is maintained, and the ability to define a fallback value (if it’s a ) is left to the final caller. Option None This is to avoid retrieving the underlying value from the Option, working with it, putting it into an Option later on, retrieving it again, putting it back into an Option again etc. Doing this is an anti-pattern and the methods ( , , and others) should be used instead. map flatMap then At some point though, you will need the value. Options of course provide a mechanism to retrieve the underlying value or a specified alternative if there is no underlying value through the method. getOrElse A quick example: const { Some, None } = require('excoptional'); // Returns Some("jackpot") or None(); const getAnOption = () => Math.random() > .5 ? Some("jackpot") : None(); // myOpt is either Some("jackpot") | None() const myOpt = getAnOption(); // get the undelrying value - "jackpot" - or default // to the provided string - no jackpot - if it's a // None. const value = myOpt.getOrElse("no jackpot"); When you need the underlying value, always use and provide an alternative value in case the is a . getOrElse Option None And Then… This implementation of also exposes a method which has similar behavior to and removes having to ask and answer the question, to or to as reviewed above. Option then Promise.then map flatMap Regardless of whether the function used to transform the underlying value returns an or not, the method will work as expected and avoid creating a nested Option. Option then A quick example: const { Some, None } = require('excoptional'); // Returns a string const appendWorld = (str) => str + " world"; // Returns an Option<string> const maybeAppendExclamationPoint = (str) => { return Math.random() > .5 ? Some(str + "!") : None(); }; // `then` works regardless of the type that the function passed to it returns const myOpt = Some("hello") .then(appendWorld) .then(maybeAppendExclamationPoint) .log(); For either function, using works correctly and won’t result in a nested . then Option will always return an Option. then always returns a promise for the same reason Promise.then Helper Methods This library exposes several additional helper methods to provide more capability and an exceptional development experience. Above there was a call to the method which conveniently console logs the Option (simpler than doing ) - and nicely formats the instance. log console.log(myOption) Similarly, there’s a method which logs the instance and returns it; extremely useful when there is a chain of method calls and you want to inspect the value at any point in that chain without breaking it apart just for debugging. logAndContinue Several other methods exist that are common to several Option libraries and Options in other languages. These include , , , etc. isSome isNone filter Take a look at the or for a complete listing of the available methods. Many of these methods have extensive documentation and examples demonstrating how they can be used. GitHub repo NPM page Conclusion Options make it easy to continually and safely manipulate a value (even when it doesn't exist) in a declarative and transparent way while preserving the context that the value may (or may not) exist throughout your code. , provides the best JavaScript and TypeScript support possible along with detailed documentation and examples. This library, excoptional It is a standalone package with 0 dependencies and 100% test coverage. I hope you find it (and more broadly, Options) useful.