npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@honeycomb-cheesecake/optional

v0.0.18

Published

Optional module for JavaScript that provides interfaces to interact with potentially null/undefined values.

Downloads

614

Readme

npm (scoped)

JavaScript Optional

Summary

Optional module for JavaScript that provides interfaces to interact with potentially null/undefined values.

It aims to take away the effort and boilerplate coding around potentially null and undefined which if not properly handled can lead to numerous runtime errors and annoyed users. Null has famously been called a "Billion Dollar Mistake" by Tony Hoare who introduced null references in ALGOL W back in 1965 because it was so easy to implement. null references are easy to drop into code, but can quickly add up to numerous errors during program runtime.

The JavaScript Optional package is heavily inspired by the scala.Option library, which really helps programmers deal with values which can be optionally set.

Defensive Programming

Vanilla JavaScript/TypeScript allows for both null and undefined values to exist, meaning that if not properly handled null errors can occur, e.g. when a property is read and/or function is called on an undefined object. This leads to defensive programming to prevent such issues, e.g.

var result = value ?? 1 * 4;

and

if(value) {
  let property = value.property;
  let result = value.someFunction();
}

Where we are checking that value has been set prior to performing any operations with it. This can add considerable boilerplate and ultimately add a lot of protective scaffolding around the code that we actually want to write. The JavaScript Option package intends to remove this scaffolding, allowing us to write code which is safe during runtime.

Installation

To install the package from the command line:

npm install @honeycomb-cheesecake/optional@[version]

To install via package.json:

"@honeycomb-cheesecake/optional": "[version]"

Usage

Objects

The JavaScript Option package exposes the IOption interface as well as the ISome and INone interfaces that implement.

| Interface | Implements | Description | | --------- | ---------- | ----------- | | IOption | | Interface to interact with potentially null and undefined values. | | ISome | IOption | Interface for values which are set. | | INone | IOption | Interface for values that have not been set. |

To create ISome and INone, respective factory methods Some and None are available:

import { IOption, None, Some }
const some: IOption<string> = Some<string>("some value");
const none: IOption<number> = None<number>();

It is important to note that ISome doesn't accept null and/or undefined and will throw an error:

import { IOption, Some }
const some: IOption<string[]> = Some<string[]>(["hello", "my", "dear"]); // Okay
Some<number[]>(null); // Throws error.
Some<string[]>(undefined); // Throws error.

In order to simplify the creation of optional values, an Option factory method is available and is recommended in most cases:

import { IOption, Option }
const some:  IOption<string> = Option<string>("some value"); // Returns an ISome<string>.
const none1: IOption<string> = Option<string>(null);         // Returns an INone<string>.
const none2: IOption<string> = Option<string>(undefined);    // Returns an INone<string>.

Other helper factories have been included to facilitate development:

import { IOption, Option, OptionEmptyString } from "@honeycomb-cheesecake/optional";
const some: IOption<string> = Option("");            // Empty string resolved to ISome<string>.
const none: IOption<string> = OptionEmptyString(""); // Empty string resolved to INone<string>.
some.forEach(value => console.log(value));  // Prints "".
none.forEach(value => console.log(value));  // No op.
import { GetOrElse } from "@honeycomb-cheesecake/optional";
console.error(GetOrElse(10, 100))        // Prints 10.
console.error(GetOrElse(null, 100))      // Prints 100.
console.error(GetOrElse(undefined, 100)) // Prints 100.
import { DoOtherwise } from "@honeycomb-cheesecake/optional";
console.log(DoOtherwise(100, (value: number) => `${value}`, () => "nothing"));       // Prints "100".
console.log(DoOtherwise(null, (value: number) => `${value}`, () => "nothing"));      // Prints "nothing".
console.log(DoOtherwise(undefined, (value: number) => `${value}`, () => "nothing")); // Prints "nothing".

Functions

id()

Returns a unique identifier for the IOption.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>(null);
const resultSome: string = valueSome.id();
const resultNone: string = valueNone.id();
console.log(resultSome); // Prints id.
console.log(resultNone); // Prints id.

isEmpty()

Returns true if value is set (i.e. of type ISome), and returns false if value isn't set (i.e. of type INone).

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>(null);
const resultSome: boolean = valueSome.isEmpty();
const resultNone: boolean = valueNone.isEmpty();
console.log(resultSome); // Prints 'false'.
console.log(resultNone); // Prints 'true'.

isDefined()

Returns false if value is set (i.e. of type ISome), and returns true if value isn't set (i.e. of type INone).

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>(null);
const resultSome: boolean = valueSome.isDefined();
const resultNone: boolean = valueNone.isDefined();
console.log(resultSome); // Prints 'true'.
console.log(resultNone); // Prints 'false'.

timestamp()

Returns the epoch timestamp number of when the IOption value was set.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
const resultSome: number = valueSome.timestamp();
const resultNone: number = valueNone.timestamp();
console.log(resultSome); // Prints timestamp.
console.log(resultNone); // Prints timestamp.

forEach()

Performs an action on the value if set without returning a value. If not set, this is a no-op.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
valueSome.forEach(value => console.log(value)); // Prints "Some value.".
valueNone.forEach(value => console.log(value)); // No op.

flatMap(func)

Performs the specified action on the value of set and returns an IOption containing the result. The action specified needs to return an IOption which differs from map() which expects the value.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<number> = Option(1);
const valueNone: IOption<number> = Option<number>();
const flatMapSome: IOption<number> = valueSome.flatMap(value => Option(value * 10)); // `ISome` containing 10 (notice how the result of the transformation is wrapped in an `Option`).
const flatMapNone: IOption<number> = valueNone.flatMap(value => Option(value * 10)); // `INone` (notice how the result of the transformation is wrapped in an `Option`).

map(func)

Performs the specified action on the value of set and returns an IOption containing the result. The action specified needs to return the value which differs from flatMap() which expects an Option wrapping the value.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<number> = Option(1);
const valueNone: IOption<number> = Option<number>();
const mapSome: IOption<number> = valueSome.map(value => value * 10); // `ISome` containing 10.
const mapNone: IOption<number> = valueNone.map(value => value * 10); // `INone`.

getOrElse(otherwiseValue)

Returns the value if ISome, and returns the specified value if INone. Think of it as get with a default if not available.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
console.log(valueSome.getOrElse("Otherwise value."));  // Prints "Some value.".
console.log(valueNone.getOrElse("Otherwise value."));  // Prints "Otherwise value.".

getOrError(otherwiseError)

Returns the value if ISome, otherwise throws the specified error if INone. Think of this as almost like a validator of presence.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
console.log(valueSome.getOrError(new Error("Something went wrong.")));  // Prints "Some value.".
console.log(valueNone.getOrError(new Error("Something went wrong.")));  // Throws error as is `None`.

getOrNull()

Returns the value if ISome, and returns null if INone.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
console.log(valueSome.getOrNull());  // Prints "Some value.".
console.log(valueNone.getOrNull());  // Prints null.

getOrUndefined()

Returns the value if ISome, and returns undefined if INone.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
console.log(valueSome.getOrUndefined());  // Prints "Some value.".
console.log(valueNone.getOrUndefined());  // Prints undefined.

doOtherwise(someFunc, noneFunc)

Executes someFunc on the value if ISome, and noneFunc if a INone.

import { IOption, Option } from "@honeycomb-cheesecake/optional";
const valueSome: IOption<string> = Option("Some value.");
const valueNone: IOption<string> = Option<string>();
console.log(valueSome.doOtherwise((value: number) => `${value}`, () => "nothing"));  // Prints "Some value.".
console.log(valueNone.doOtherwise((value: number) => `${value}`, () => "nothing"));  // Prints "nothing".