This is Perhaps
Perhaps is a lightweight Maybe
type implementation for handling optional values in TypeScript. I designed the Maybe
type to manage situations where values may be present or absent more gracefully and robustly, based on Haskall’s Maybe
type monad.
Installation
Install Perhaps via npm:
npm install perhaps-ts
Usage
Creating Maybe
Instances
Creating Maybe
instances is straightforward. You can use the static methods Just
and Nothing
or their corresponding helper functions.
import { Maybe, Just, Nothing } from "perhaps-ts";
// Using static methodsconst maybeValue = Maybe.Just(5);const noValue = Maybe.Nothing<number>();
// Using helper functionsconst anotherMaybeValue = Just(10);const anotherNoValue = Nothing<string>();
Checking for Values
To determine if a Maybe
instance has a value (Just
) or is empty (Nothing
), use the IsJust
and IsNothing
methods.
if (maybeValue.IsJust()) console.log("This is Just:", maybeValue.FromJust());if (noValue.IsNothing()) console.log("This is Nothing");
Retrieving Values
To safely retrieve the value from a Just
instance, use the FromJust
or ToChecked
methods. Be cautious, as these methods will throw an error if called on a Nothing
instance.
try { const value = maybeValue.FromJust(); console.log("Value:", value);} catch (error) { console.error(error.message);}
try { const value = noValue.ToChecked();} catch (error) { console.error(error.message); // Maybe: Attempted to access value of Nothing}
Default Values
Provide a default value when dealing with Maybe
instances to ensure you always have a fallback.
const valueOrDefault = noValue.FromMaybe(42);console.log("Value or Default:", valueOrDefault); // Outputs: 42
Conditional Value Extraction
Extract the value into an output object conditionally if the instance is Just
.
const output = {};if (maybeValue.To(output)) { console.log("Extracted Value:", output.value); // Extracted Value: 5} else { console.log("No value to extract");}
Alternatively, use the To
method with a custom key.
type Output = { data?: number };
const output: Output = {};if (maybeValue.To(output, "data")) { console.log("Extracted Data:", output.data); // Extracted Data: 5} else { console.log("No data to extract");}
Equality Comparisons
Compare Maybe
instances for equality with the equals
and notEquals
methods.
const maybe1 = Just(5);const maybe2 = Just(5);const maybe3 = Nothing<number>();
console.log(maybe1.equals(maybe2)); // trueconsole.log(maybe1.equals(maybe3)); // falseconsole.log(maybe1.notEquals(maybe3)); // true
Practical Function Examples
Here are some examples of how to write functions that return Maybe<T>
instead of T | false
, and how to handle these returned values.
Example Function Returning Maybe<T>
A function that searches for an item in an array and returns a Maybe<T>
instead of the item or false
.
import { Maybe, Just, Nothing } from "perhaps-ts";
function findItem<T>(array: T[], predicate: (item: T) => boolean): Maybe<T> { for (const item of array) { if (predicate(item)) { return Just(item); } } return Nothing<T>();}
// Usage exampleconst numbers = [1, 2, 3, 4, 5];
const result = findItem(numbers, (n) => n === 3);if (result.IsJust()) { console.log("Found:", result.FromJust()); // Found: 3} else { console.log("Item not found");}
Handling and Checking Maybe<T>
Values
Use IsJust
and IsNothing
to handle Maybe<T>
values.
const maybeNumber = findItem(numbers, (n) => n === 6);
if (maybeNumber.IsJust()) { console.log("Found:", maybeNumber.FromJust());} else { console.log("Item not found");}
Use FromMaybe
with a default value.
const valueOrDefault = maybeNumber.FromMaybe(0);console.log("Value or Default:", valueOrDefault); // Value or Default: 0
Use To
for conditional extraction.
const output = {};if (maybeNumber.To(output)) { console.log("Extracted Value:", output.value);} else { console.log("No value to extract");}
Another Function Example
A function that parses an integer from a string and returns Maybe<number>
.
function parseIntMaybe(input: string): Maybe<number> { const parsed = parseInt(input, 10); if (isNaN(parsed)) { return Nothing<number>(); } return Just(parsed);}
// Usage exampleconst maybeParsed = parseIntMaybe("123");if (maybeParsed.IsJust()) { console.log("Parsed integer:", maybeParsed.FromJust()); // Parsed integer: 123} else { console.log("Failed to parse integer");}
const maybeFailedParsed = parseIntMaybe("abc");console.log("Parsed or Default:", maybeFailedParsed.FromMaybe(0)); // Parsed or Default: 0
Returning Maybe<T>
from Asynchronous Functions
Using Maybe<T>
in an asynchronous function.
async function fetchData(url: string): Promise<Maybe<string>> { try { const response = await fetch(url); if (!response.ok) { return Nothing<string>(); } const data = await response.text(); return Just(data); } catch (error) { return Nothing<string>(); }}
// Usage examplefetchData("https://api.example.com/data").then((maybeData) => { if (maybeData.IsJust()) { console.log("Fetched Data:", maybeData.FromJust()); } else { console.log("Failed to fetch data"); }});
API Reference
Maybe
Class
Static Methods
Maybe.Just(value: T): Maybe<T>
: Creates aJust
instance containing the provided value.Maybe.Nothing<T>(): Maybe<T>
: Creates aNothing
instance with no value.
Instance Methods
IsJust(): boolean
: Returnstrue
if the instance isJust
, otherwisefalse
.IsNothing(): boolean
: Returnstrue
if the instance isNothing
, otherwisefalse
.FromJust(): T
: Returns the value if the instance isJust
, otherwise throws an error.ToChecked(): T
: Alias forFromJust
.FromMaybe(defaultValue: T): T
: Returns the value if the instance isJust
, otherwise returns the provided default value.To(out: { value?: T }): boolean
: If the instance isJust
, sets the value in the provided output object and returnstrue
, otherwise returnsfalse
.equals(other: Maybe<T>): boolean
: Returnstrue
if the otherMaybe
instance is equal, otherwisefalse
.notEquals(other: Maybe<T>): boolean
: Returnstrue
if the otherMaybe
instance is not equal, otherwisefalse
.
I built Perhaps to simplify handling optional values in TypeScript, providing a clear and expressive way to manage cases where a value may or may not be present. It is built to help you write more robust and expressive code.
Cheers.