@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:
Option
offers 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.
None
can not be confused withfalse
,0
or""
.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/option
Import 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
Option
value.
Trying to accessvalue
on aNone
will 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
true
it 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
true
it 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
None
if 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 asbind
orflatMap
.Returns
None
if 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): T
Returns the contained value if this is a
Some
, otherwise returnsor
.
equals(option): boolean
equals(option: Option<T>): boolean
Returns
true
if 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>): U
Extracts 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
Option
of typeSome
. This is the preferred way to create newSome
:s
none(): Option
none<T>(): Option<T>
Constructs a new
Option
of 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
None
if value is eithernull
orundefined
. Otherwise returns aSome
containing the value.
fromEmpty(value): Option
fromEmpty<T extends Record<'length', number>>(xs: T): Option<T>
Takes a value with property
length: number
and returnsNone
if length is zero or less. Otherwise returns aSome
of 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>): boolean
Operator alias of the
isSome
property. Returnstrue
if 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>): boolean
Operator alias of the
isNone
property. Returnstrue
if 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>) => T
Curried 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>) => U
Curried 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
None
if option isNone
, or ifvalue[property]
is eithernull
orundefined
. Otherwise returns aSome
of the extracted value.
filter (predicate) (option): Option
filter<T> (predicate: (x: T) => boolean): (option: Option<T>) => Option<T>
Calls
predicate
with the contained value.Returns
None
ifpredicate
is false, otherwise returns the option.
or (b) (a): Option
or<T> (b: Option<T>): (a: Option<T>) => Option<T>
Returns option
a
if 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
b
if optiona
is aSome
, otherwiseNone
.