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

monadix

v1.0.6

Published

Functional TypeScript utility types such as Option, Result and others.

Downloads

37

Readme

Monadix

Functional TypeScript utility types such as Option, Result and others. Focusing on the most practical usage.

Table of Contents

The Option Monad

The Option monad is a way to handle optional values in a functional and composable way. It provides a standard interface for dealing with values that may or may not exist, without resorting to null or undefined.

To create a value that exists, use the some function, to create a value that does not exist, use the none constant:

import { some, none } from 'monadix/option';

const value = some(42);
const emptyValue = none;

You can then use the map method to transform the value:

const transformed = value.map(x => x * 2);

The transformed variable now contains a new Option value that represents the result of doubling the original value. If the original value did not exist, the transformed value will also not exist.

You can use the chain method to chain operations that return Option values:

const result = value.chain(x => some(x * 2)).chain(x => some(x.toString()));

The result variable now contains a new Option value that represents the result of doubling the original value, and then converting it to a string. If the original value did not exist, the result will also not exist.

You can use the getOrElse method to get the value if it exists, or a default value if it does not:

const value = some(42);
const result = value.map(x => x * 2).getOrElse(0);

The result variable now contains the value 84, because the original value existed.

You can use the getOrThrow method to get the value if it exists, or throw an error if it does not:

const value = some(42);
const result = value.map(x => x * 2).getOrThrow();

The result variable now contains the value 84, because the original value existed.

Finally, you can use the isPresent method to check if the value exists:

const value = some(42);

if (value.isPresent()) {
  console.log(value.get())
}

The Result monad

The Result monad is a functional programming concept that is used to handle the outcome of operations that can either succeed or fail. It is similar to the Option monad, but includes an customized error message in the case of failure.

Most common use of the Result monad is to have a function that returns some value or an error.

For example:

import { success, fail, Result } from 'monadix/result';

function divide(a: number, b: number): Result<number, string> {
  if (b === 0) {
    return fail('Cannot divide by zero');
  }
  
  return success(a / b);
}

Once a Result instance is created, you can use the map, orElse, and chain methods to perform operations on the value or error message. The match method can be used to pattern match on the value of the Result.

const okResult = divide(10, 5);

const mappedResult = okResult.map(value => value * 2);
// Returns a new Result instance with the value 4

const chainedResult = okResult.chain(value => divide(value, 2));
// Returns a new Result instance with the value 1

const matchedResult = okResult.match({
  success: value => `Result is ${value}`,
  fail: error => `Error: ${error}`,
});
// Returns the string 'Result is 2'

const failResult = divide(10, 0);

const mappedError = failResult.orElse(error => error.toUpperCase());
// Returns a new Result instance with the error message 'CANNOT DIVIDE BY ZERO'

You can also use the getOrElse, and getOrThrow methods to handle the Result instance if you want to be more imperative.

For example:

import { success, fail, Result } from 'monadix/result';

const okResult = divide(10, 5);

console.log(`Result is ${result.getOrElse(0)}`);
console.error(`Error: ${result.getOrThrow()}`);
}
// Logs 'Result is 2'

Also, you can use the isSuccess, isFail method to imperatively check for errors.

For example:

import { success, fail, Result } from 'monadix/result';

const okResult = divide(10, 5);

if (orResult.isSuccess()) {
  console.log(`Result is ${result.get()}`);
} else {
  console.error(`Error: ${result.err()`);
}
// Logs 'Result is 2'

Utility functions

There are some utility functions to bridge the world if imperative programming.

fromNullable

The fromNullable function creates a new Option or Result instance from a nullable value. If the value is null or undefined, the function returns an Option/Result instance containing none or fail. If the value is not null or undefined, the function returns an Option/Result instance containing some(value) or success(value).

Example:

import { success, fail, fromNullable } from 'monadix/result';

interface User {
  name: string;
  email: string;
}

const getUserById(id: number): User | null => {
  // ...
}

const user = fromNullable(getUserById(42)).orElse(
  () => fail(new Error('User not found'));
);

fromPromise

Helps to create Option or Result from promises.

Example:

import { success, fail, fromPromise, Result } from 'monadix/result';

interface User {
  name: string;
  email: string;
}

function getUserById(id: number): Promise<User> {
  // ...
}

const userResult = await fromPromise(getUserById(42)).orElse(
  (error) => fail(new Error('Failed to get user: ' + error.message));
);

userResult.match({
  success(user) {
    console.log('Got user:', user);
  },
  fail(error) {
    console.error('Failed to get user:', error);
  }
});

Troubleshooting

TypeScript Error: Cannot find module 'monadix/option' or its corresponding type declarations

If you receive an error message indicating that the module cannot be found, most likely your moduleResolution setting in tsconfig.json is not configured correctly. This package requires the use of Node.js version 16 or later.

To resolve this issue, ensure that your tsconfig.json file includes the following setting:

{
  "compilerOptions": {
    "moduleResolution": "nodenext" // or "node2022"
  }
}

If you continue to experience issues, please open an issue and provide as much detail as possible about your environment and the steps you have taken to reproduce the error.

Contributions

Contributions are welcome and encouraged! Here are a few guidelines to get started:

  1. Fork the repository and create a new branch for your contribution.
  2. Write tests for your contribution and make sure all existing tests pass.
  3. Ensure that your code adheres to the existing coding standards and conventions.
  4. Submit a pull request with a clear description of your changes.

If you encounter any issues or have any questions, please feel free to open an issue or contact me.