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

@tamerfrombk/optional

v2.0.0

Published

A minimal implementation of an Optional data type mirroring Java 11's optional.

Downloads

3

Readme

Optional

A minimal implementation of an Optional data type mirroring Java 11's optional.

Quickstart

npm i @tamerfrombk/optional

Features

  1. Lightweight
    • typescript is the only dependency!
    • single source file: src/optional.{ts,js}
  2. Functional
    • the Optional type does not mutate itself and follows functional programming best practices
  3. No surprises!
    • The library works as you'd expect it to per PLA.

Examples

Constructing an Optional

// opt is an Optional<string> holding the value 'abc'
const opt: Optional<string> = Optional.of('abc');

// False-y values must use ofFalsy() or an exception will be thrown
const opt2: Optional<string> = Optional.ofFalsy('');

Manipulating an Optional

const mapper = (s) => s + ' def';

// value will be 'abc def'
const value: string = Optional.of('abc').map(mapper).orElse('other');

// otherValue will be 'other'
const otherValue: string = Optional.ofFalsy('').map(mapper).orElse('other');

Dealing with potentially "falsy" values

const value: string = myServiceThatCanReturnFalsy.doSomething(...);

// safeValue will be 'foo' in case of a falsy value
// or a value that is not equal to 'abc' with the mapper applied to it
const safeValue = Optional.ofFalsy(value)
    .filter(s => s !== 'abc')
    .map(s => /* do something with s */)
    .orElse('foo');

Philosophy

Tony Hoare, a computer scientist that invented ALGOL in 1965, famously gave a talk in 2009 where he apologizes for having null in the language and called it his "billion dollar mistake". You've probably felt the effects of his "mistake" when your program either mysteriously crashes or throws a NullPointerException; this is usually due to forgetting to check whether a certain object was null before using it. This is a common defensive programming pitfall.

The truth of the matter is that defensive programming is only going to be so effective: programmers are still human and humans forget things all the time. So what do we do if defensive programming won't help us much? We turn to computers -- more specifically compilers -- for help.

The Optional data type is inspired by the functional programming equivalent of a Maybe data type; it represents the idea of a value possibly existing right into the type system. This means that the compiler can help us catch null errors during compilation before the program is ever shipped.

Let's walk through a quick example.

Suppose you have the following service:

class AccountService {
  findById(id: number): Account {
    // implementation
  }
}

The returned Account object may or may not be there and we have to deal with both of those possibilities. We can deal with it either by checking for the "truthyness" of the Account each time we call findById or we can have findById do the check and throw if the account could not be found. If we decide to throw, we have now opened another can of worms for us to deal with.

This is exactly where Optional shines; instead of throwing or repeatedly checking the Account, we ask the type system for help:

import { Optional } from '@tamerfrombk/optional';

class AccountService {
  findById(id: number): Optional<Account> {
    return Optional.ofFalsy(/* implementation */);
  }
}

In our client code, if we try to treat the Optional as an Account, we'll get a compile time error:

import AccountService from './services/AccountService';

function myFunction() {
  const account = AccountService.findById(0);

  const balance = account.deposit(100); // compiler error -- no deposit() method on Optional
}

The compiler is forcing us to deal with the possibility the Account may not exist thanks to the Optional type. Here's one way of handling this possibility:

import AccountService from './services/AccountService';

function myFunction() {
  const balance = AccountService.findById(0)
    .map((a) => a.deposit(100))
    .orElse(-1);
}

Now we've made handling the possibility of a missing account explicit.

Contributing

  1. Create a feature/issue on GitHub.
  2. Create a PR addressing the feature/issue.
  3. Have it reviewed and merged :)