0.16.1 • Published 11 months ago

@fp-utils/option v0.16.1

Weekly downloads
-
License
MIT
Repository
github
Last release
11 months ago

Option

Option represents the presence of a value Some or the absence of a value None. It's commonly utilized to manage computations that might or might not yield a result, or those that could potentially fail.

Option is particularly useful, when dealing with operations that may return null or undefined values, providing a structured and safe approach to manage such scenarios.

By using option, the need for imperative and explicit null or undefined checks diminishes, reducing code noise and allowing for clearer focus on essential domain logic. Essentially, the Option enables to focus primarily on the 'happy path'.

import { Option } from "@fp-utils/option";

type BookId = number;
type BookName = string;

const books = new Map<BookId, BookName>([
  [1, "The Hobbit"],
  [2, "The Fellowship of the Ring"],
]);

const tryGetBook = (id: BookId): Option<BookName> => Option.from(books.get(id));

// Evaluates to None
const bookNotFound = tryGetBook(0);

// Evaluates to Some "The Hobbit"
const bookFound = tryGetBook(1);

Usage

Constructors

Similar as how String or Number constructors are used in JavaScript:

Use Some(42) constructor to wrap a value for existing value and for non-existent value use the static None class.

import { None, Some } from "@fp-utils/option";

const some = Some(42);
const none = None;

Option methods

Option methods are chainable functions that allow for a sequence of operation with the contained value T in the Option.

Option.filter

Signature: (predicate: (value: T) => boolean): boolean

Option.filter returns a boolean that is evaluated with the given predicate function which is applied on the option value T. None evaluates to false.

import { None, Some } from "@fp-utils/option";

Some(2)
  .filter((x) => x >= 5); // evaluates to false

Some(42)
  .filter((x) => x >= 5); // evaluates to true

None
  .filter((x) => x >= 5); // evaluates to false

Option.flatMap

Signature: <U>(fn: (value: T) => Option<U>): Option<U>

Option.flatMap applies a function fn to the content of option T and transforms it into an option U.

import { None, Option, Some } from "@fp-utils/option";

type TryParse = (input: string) => Option<number>;

const tryParse: TryParse = (input: string) => {
  const value = parseInt(input);
  return isNaN(value) ? None : Some(value);
};

Some("42")
  .flatMap(tryParse); // Evaluates to Some 42

Some("Forty-two")
  .flatMap(tryParse); // Evaluates to None

None
  .flatMap(tryParse); // Evaluates to None

Option.inspect

Signature: (fn: (value: T) => void): Option<T>

Option.inspect calls the provided function fn with a reference to the contained option value T if the option is some.

import { None, Some } from "@fp-utils/option";

Some(42)
  .inspect((x) => console.log(x * 2)); // Prints 84

None
  .inspect((x) => console.log(x * 2)); // Prints nothing

Option.isNone

Signature: (): this is None

Option.isNone returns true if the option is None

import { None, Some } from "@fp-utils/option";

Some(42).isNone(); // Evaluates to false

None.isNone(); // Evaluates to true

Option.isSome

Signature: <T>(): this is Some<T>

Option.isSome returns true if the option is Some

import { None, Some } from "@fp-utils/option";

Some(42).isSome(); // Evaluates to true

None.isSome(); // Evaluates to false

Option.map

Signature: <U>(fn: (value: T) => U): Option<U>

Option.map applies a function fn to option value T and transforms it into value U.

import { None, Some } from "@fp-utils/option";

Some(42)
  .map((x) => x * 2); // Evaluates to Some 84

None
  .map((x) => x * 2); // Evaluates to None

Option.match

Signature: <U1, U2>(onSome: (value: T) => U1, onNone: () => U2): U1 | U2

Option.match transforms the option value T into U1 using onSome and then returns U1. If the option is None, onNone is called and U2 returned.

import { None, Some } from "@fp-utils/option";

Some(42)
  .match((x) => x * 2, () => 99); // Evaluates to 84

None
  .match((x) => x * 2, () => 99); // Evaluates to 99

Option.toJSON

Signature: (): T | null

Option.toJSON serializes the option into JSON format. If the option is None, it will be serialized to null. If the option is Some, it will be serialized to the unwrapped value T.

import { None, Some } from "@fp-utils/option";

Some(42)
  .toJSON(); // Evaluates to 42

None
  .toJSON(); // Evaluates to null

Option.toString

Signature: (): "Some(value)" | "None"

Option.toString returns the string representation of the result and the stringified value as Some(value) if the result is Some or None if the result is None.

import { None, Some } from "@fp-utils/option";

Some(42)
  .toString(); // Evaluates to "Some(42)"

None
  .toString(); // Evaluates to "None"

Option.unwrap

Signature: (): T

Option.unwrap returns the value T from the associated option if it is Some; otherwise it will throw.

import { None, Some } from "@fp-utils/option";

Some(42).unwrap(); // Evaluates to 42

None.unwrap(); // Throws an exception!

Option.unwrapOr

Signature: (defaultValue: T): T

Option.unwrapOr returns the value T from the associated option or returns the default value if the option is None.

import { None, Some } from "@fp-utils/option";

Some(42).unwrapOr(99); // Evaluates to 42

None.unwrapOr(99); // Evaluates to 99

Option.zip

Signature: <U>(option: Option<U>): Option<[T, U]>

Option.zip combines two option values into a tuple and returns the tuple wrapped in Option.

import { None, Some } from "@fp-utils/option";

Some(42).zip(Some(84)); // Evaluates to Some<[42, 84]>

Some(42).zip(None); // Evaluates to None

None.zip(Some(84)); // Evaluates to None

Option higher-order functions

Option higher-order functions allow for Option value T chainability within callbacks like Promise.then.

import { Option } from "@fp-utils/option";

Promise.resolve(42)
  .then(Option.from)
  .then(Option.inspect(console.log))
  .then(Option.map((value) => value + 10))
  .then(Option.unwrap); // Evaluates to 52

Option.filter

Signature: (predicate: (value: T) => boolean): (option: Option<T>) => boolean

Option.filter returns a boolean that is evaluated with the given predicate function which is applied on the option value T. None evaluates to false.

import { None, Option, Some } from "@fp-utils/option";

Option
  .filter((x: number) => x >= 5)(Some(2)); // evaluates to false

Option
  .filter((x: number) => x >= 5)(Some(42)); // evaluates to true

Option
  .filter((x: number) => x >= 5)(None); // evaluates to false

Option.flatMap

Signature: flatMap(fn: (value: T) => Option<U>): (option: Option<T>) => Option<U>

Option.flatMap applies a function fn to the content of option T and transforms it into an option U.

import { None, Option, Some } from "@fp-utils/option";

type TryParse = (input: string) => Option<number>;

const tryParse: TryParse = (input: string) => {
  const value = parseInt(input);
  return isNaN(value) ? None : Some(value);
};

Option
  .flatMap(tryParse)(Some("42")); // Evaluates to Some 42

Option
  .flatMap(tryParse)(Some("Forty-two")); // Evaluates to None

Option
  .flatMap(tryParse)(None); // Evaluates to None

Option.inspect

Signature: inspect(fn: (value: T) => void): (option: Option<T>) => Option<T>

Option.inspect calls the provided function fn with a reference to the contained option value T if the option is some.

import { None, Option, Some } from "@fp-utils/option";

Option
  .inspect((x: number) => console.log(x * 2))(Some(42)); // Prints 84

Option
  .inspect((x: number) => console.log(x * 2))(None); // Prints nothing

Option.map

Signature: map(fn: (value: T) => U): (option: Option<T>) => Option<U>

Option.map applies a function fn to option value T and transforms it into value U.

import { None, Option, Some } from "@fp-utils/option";

Option
  .map((x: number) => x * 2)(Some(42)); // Evaluates to Some 84

Option
  .map((x: number) => x * 2)(None); // Evaluates to None

Option.match

Signature: match(onSome: (value: T) => U1, onNone: () => U2): (option: Option<T>) => U1 | U2

Option.match transforms the option value T into U1 using onSome and then returns U1. If the option is None, onNone is called and U2 returned.

import { None, Option, Some } from "@fp-utils/option";

Option
  .match((x: number) => x * 2, () => 99)(Some(42)); // Evaluates to 84

Option
  .match((x: number) => x * 2, () => 99)(None); // Evaluates to 99

Option.unwrapOr

Signature: unwrapOr(defaultValue: T): (option: Option<T>) => T

Option.unwrapOr returns the value T from the associated option or returns the default value if the option is None.

import { None, Option, Some } from "@fp-utils/option";

Option
  .unwrapOr(99)(Some(42)); // Evaluates to 42

Option
  .unwrapOr(99)(None); // Evaluates to 99

Option.zip

Signature: zip<U>(option: Option<U>): (option: Option<T>) => Option<[T, U]>

Option.zip combines two option values into a tuple and returns the tuple wrapped in Option.

import { None, Option, Some } from "@fp-utils/option";

Option
  .zip(Some(84))(Some(42)); // Evaluates to Some<[42, 84]>

Option
  .zip(None)(Some(42)); // Evaluates to None

Option
  .zip(Some(84))(None); // Evaluates to None

Option static methods

Static methods for working with options.

Option.all

Signature: all(options: Option<T>[]): Option<T[]>

Option.all returns all Some option values as an array within a Some option. If None option exists in the array, None is returned. An empty array signifies success, resulting in a Some with an empty array.

import { None, Option, Some } from "@fp-utils/option";

Option
  .all([]); // Evaluates to Some []

Option
  .all([Some(10), Some(42), Some(84)]); // Evaluates to Some [10, 42, 84]

Option
  .all([Some(10), Some(42), None, Some(84)]); // Evaluates to None

Option
  .all([None]); // Evaluates to None

Option.any

Signature: any(options: Option<T>[]): Option<T>

Option.any returns the first Some option encountered. If no Some options are found in the array None is returned.

import { None, Option, Some } from "@fp-utils/option";

Option
  .any([]); // Evaluates to None

Option
  .any([Some(10), Some(42), Some(84)]); // Evaluates to Some 10

Option
  .any([Some(10), Some(42), None, Some(84)]); // Evaluates to None

Option
  .any([None]); // Evaluates to None

Option.from

Signature: from(value: T | (() => T)): From<T>

Option.from converts a nullable value, non-nullable value, a function or a promise to an option.

import { Option } from "@fp-utils/option";

Option
  .from(undefined); // Evaluates to None

Option
  .from(null); // Evaluates to None

Option
  .from(42); // Evaluates to Some 42

Option
  .from(() => 42); // Evaluates to Some 42

Option
  .from(() => Promise.resolve(42)); // Evaluates to Promise<Some 42>

Option
  .from(() => Promise.reject()); // Evaluates to Promise<None>

Option
  .from(Promise.resolve(42)); // Evaluates to Promise<Some 42>

Option
  .from(Promise.resolve(undefined)); // Evaluates to Promise<None>

Option
  .from(Promise.reject()); // Evaluates to Promise<None>

Option.isNone

Signature: isNone(option: Option<T>): option is None

Option.isNone returns true if the option is None

import { None, Option, Some } from "@fp-utils/option";

Option
  .isNone(Some(42)); // Evaluates to false

Option
  .isNone(None); // Evaluates to true

Option.isSome

Signature: isSome(option: Option<T>): option is Some<T>

Option.isSome returns true if the option is Some

import { None, Option, Some } from "@fp-utils/option";

Option
  .isSome(Some(42)); // Evaluates to true

Option
  .isSome(None); // Evaluates to false

Option.none

Signature: none(): None

Option.none returns a None option.

import { Option } from "@fp-utils/option";

Option
  .none(); // Evaluates to None

Option.some

Signature: some(value: NonNullable<T>): Some<NonNullable<T>>

Option.some creates an option Some with value T.

import { Option } from "@fp-utils/option";

Option
  .some(42); // Evaluates to Some 42

Option
  .some(undefined); // Throws an exception or compiler error!

Option
  .some(null); // Throws an exception or compiler error!

Option.toJSON

Signature: toJSON(option: Option<T>): T | null

Option.toJSON serializes the option into JSON format. If the option is None, it will be serialized to null. If the option is Some, it will be serialized to the unwrapped value T.

import { None, Option, Some } from "@fp-utils/option";

Option
  .toJSON(Some(42)); // Evaluates to 42

Option
  .toJSON(None); // Evaluates to null

Option.toString

Signature: toString(option: Option<T>): "Some(value)" | "None"

Option.toString returns the string representation of the result and the stringified value as Some(value) if the result is Some or None if the result is None.

import { None, Option, Some } from "@fp-utils/option";

Option
  .toString(Some(42)); // Evaluates to "Some(42)"

Option
  .toString(None); // Evaluates to "None"

Option.unwrap

Signature: unwrap(option: Option<T>): T

Option.unwrap returns the value T from the associated option if it is Some; otherwise it will throw.

import { None, Option, Some } from "@fp-utils/option";

Option
  .unwrap(Some(42)); // Evaluates to 42

Option
  .unwrap(None); // Throws an exception!
0.14.0

1 year ago

0.15.0

1 year ago

0.16.0

1 year ago

0.16.1

11 months ago

0.13.1

1 year ago

0.13.0

1 year ago

0.12.0

1 year ago

0.11.1

1 year ago

0.11.0

1 year ago

0.10.0

1 year ago

0.9.0

1 year ago

0.8.0

1 year ago

0.7.0

1 year ago

0.6.0

1 year ago

0.5.0

1 year ago

0.4.0

2 years ago

0.3.0

2 years ago

0.2.0

2 years ago

0.1.0

2 years ago

0.1.0-bd6b87c

2 years ago