@dise-international/option v0.3.0
Option
Option is a data structure heavily inspired by the Rust Option enum that encodes values that either exist or not. Sometimes called Maybe, it's made up of a tagged union with two variants:
Some (x), representing the presence of a valueNone, representing the absence of a value.
Option is useful in place of values like null or undefined, and carry several benefits:
Optionoffers semantic information to the developer -Option<number>tells us both that it is anOption, and that it should contain a number.- It forces us to deal with the absence of a value, while providing ergonomic, expressive ways to do so.
Nonecan not be confused withfalse,0or"".Some(0)is vastly different fromNone.
Similar to @dise-international/result, the Option instance implements only a few basic methods and properties, while more expressive functions are implemented as static methods. This is to keep the actual class instance clean, and to promote piping values through functional transformations.
Installation
@dise-international/option is available in both TypeScript and JavaScript format.
Install via NPM
$ npm install @dise-international/optionImport the module
import { Option } from '@dise-international/option';Or require it
const { Option } = require('@dise-international/option');Usage
The guide, and the examples in it, assumes a TypeScript environment. If you're using plain JavaScript, the guide reads exactly the same, but without type declarations and generics.
Imports / Exports
The module exports three members; Option, Some, and None, where the latter two are symbols used to tag an Option as either variant. All of the functionality is implemented as properties, methods, or static functions on Option.
Imports are omitted from the code examples below, unless there is special reason to include them. If none are present in the example, assume that there is an implicit:
import { Option, Some, None } from '@dise-international/option';Variants
None
A unique symbol representing the absence of a value. Exported alongside
Option.
Examples
import { None, Option } from '@dise-international/option';
const option = new Option<number>(None);
assert.isTrue(option.isNone);Some
A unique symbol representing the presence of a value. Exported alongside
Option.
Examples
import { None, Option } from '@dise-international/option';
const option = new Option<number>(Some, 1);
assert.isTrue(option.isSome);Properties
The properties implemented on the Option instance are listed here.
type: Symbol
A symbol that tags the Option as either Some or None.
Set during construction.
const some = Option.some<number>(1);
assert.equals(some.type, Some);
const none = Option.none<number>(1);
assert.equals(none.type, None);value: T | never
Contains the
Optionvalue.
Trying to accessvalueon aNonewill result in an error
Examples
const some = Option.some<number>(1);
assert.equals(some.value, 1);
const none = Option.none<number>();
assert.throws(() => none.value, 'Can not read value from None');isSome: boolean
Returns
trueit the type isSome.
Examples
const some = Option.some<number>(1);
assert.isTrue(some.isSome);
const none = Option.none<number>();
assert.isFalse(none.isSome);isNone: boolean
Returns
trueit the type isNone.
Examples
const some = Option.some<number>(1);
assert.isFalse(some.isNone);
const none = Option.none<number>();
assert.isTrue(none.isNone);Methods
The methods implemented on the Option instance are listed here.
T refers to Option<T>, the dynamic type of the contained value.
map(fn): Option
map<U>(fn: (x: T) => U): Option<U>Maps this
Option<T>toOption<U>by applying a function to the contained value and wrapping it in anOption.Returns
Noneif this is aNone, otherwise returnsSome.
Examples
const some = Option.some<number>(1)
.map<string>(x => x.toString());
assert.equals(some.value, "1");const none = Option.none<number>()
.map<string>(x => x.toString());
assert.throws(() => none.value, 'Can not read value from None');chain(fn): Option
chain<U>(fn: (x: T) => Option<U>): Option<U>Maps this
Option<T>toOption<U>by applying a function to the contained value. Commonly referred to asbindorflatMap.Returns
Noneif this is aNone, otherwise returns the result offn.
Examples
Type declarations may be omitted for brevity.
Conditionally turn a Some into a None
const some = Option.some(1);
const none = some.chain(x => x > 5
? Option.some(x)
: Option.none());
assert.isTrue(none.isNone);Compose with Option.some to form map()
const map = (option, fn) => Option.some(option.chain(fn));
const some = map(
Option.some(1)
x => x.toString())
assert.equals(some.value, "1");Use with the identity function to form flatten()
const flatten = (option) => option.chain(x => x);
const maybeNumber: Option<Option<number>> = Option.some(Option.some(1))
assert.equals(flatten(maybeNumber).value, 1);unwrapOr(or: T): T
unwrapOr(or: T): TReturns the contained value if this is a
Some, otherwise returnsor.
equals(option): boolean
equals(option: Option<T>): booleanReturns
trueif both options areNone, or when the contained values are strictly equal. Otherwise returnsfalse.
| a | b | = |
|---|---|---|
None | None | ✔️ |
None | Some | ❌ |
Some (a) | Some (a) | ✔️ |
Some (a) | Some (b) | ❌ |
match\(pattern): U
match<U>(pattern: Record<'Some'|'None', (x?: T) => U>): UExtracts the contained value by matching on the provided pattern and applying the function.
Examples
const some = Option.some<number>(1);
const value = some.match({
Some: x => x,
None: () => 0
});
assert.equals(value, 1);const none = Option.none<number>();
const value = none.match({
Some: x => x,
None: () => 0
});
assert.equals(value, 0);Operators
The functions implemented as static methods on the Option class are listed here.
some(value): Option
some<T>(value: T): Option<T>Constructs a new
Optionof typeSome. This is the preferred way to create newSome:s
none(): Option
none<T>(): Option<T>Constructs a new
Optionof typeNone. This is the preferred way to create newNone:s
of(value): Option
of<T>(value: T): Option<T>Alias for Option.some.
from(value): Option
from<T>(x: T): Option<T>Returns
Noneif value is eithernullorundefined. Otherwise returns aSomecontaining the value.
fromEmpty(value): Option
fromEmpty<T extends Record<'length', number>>(xs: T): Option<T>Takes a value with property
length: numberand returnsNoneif length is zero or less. Otherwise returns aSomeof that value.
Examples
const nonEmptyString: Option<string> = Option.fromEmpty("Hello");
assert.isTrue(nonEmptyString.isSome);
const emptyString: Option<string> = Option.fromEmpty("");
assert.isTrue(emptyString.isNone);const nonEmptyList: Option<string[]> = Option.fromEmpty(["Hello", "World"]);
assert.isTrue(nonEmptyList.isSome);
const emptyList: Option<string[]> = Option.fromEmpty([]);
assert.isTrue(emptyList.isNone);isSome(option): boolean
isSome(option: Option<any>): booleanOperator alias of the
isSomeproperty. Returnstrueif the option is aSome, otherwise returnsfalse.
Examples
const some = Option.some<number>(1);
assert.isTrue(Option.isSome(some));isNone(option): boolean
isNone(option: Option<any>): booleanOperator alias of the
isNoneproperty. Returnstrueif the option is aNone, otherwise returnsfalse.
Examples
const none = Option.none<number>();
assert.isTrue(Option.isNone(none));map (fn) (option): Option
map<T, U>(fn: (x: T) => U): (option: Option<T>) => Option<U>Curried operator alias of the
map()method. Takes option as it's second parameter.
chain (fn) (option): Option
chain<T, U>(fn: (x: T) => Option<U>): (option: Option<T>) => Option<U>Curried operator alias of the
chain()method. Takes option as it's second parameter.
unwrapOr (or) (option): T
unwrapOr<T>(or: T): (option: Option<T>) => TCurried operator alias of the
unwrapOr()method. Takes option as it's second parameter.
match (pattern) (option): T
match<T, U>(pattern: pattern: Record<'Some'|'None', (x?: T) => U>): (option: Option<T>) => UCurried operator alias of the
match()method. Takes option as it's second parameter.
prop (property) (option): T
prop<T> (property: string): (option: Option<{[key: string]: T}>) => Option<T>Extracts valueproperty from the option.
Returns
Noneif option isNone, or ifvalue[property]is eithernullorundefined. Otherwise returns aSomeof the extracted value.
filter (predicate) (option): Option
filter<T> (predicate: (x: T) => boolean): (option: Option<T>) => Option<T>Calls
predicatewith the contained value.Returns
Noneifpredicateis false, otherwise returns the option.
or (b) (a): Option
or<T> (b: Option<T>): (a: Option<T>) => Option<T>Returns option
aif it is aSome, otherwise returns optionb.
orElse (f) (option): Option
orElse<T> (f: () => Option<T>): (option: Option<T>) => Option<T>Returns the option if it is a
Some, otherwise returnsf().
and (b) (a): Option
and<T> (b: Option<T>): (a: Option<T>) => Option<T>Returns option
bif optionais aSome, otherwiseNone.