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

try-typescript

v0.7.0

Published

This repository implements a Try class inspired by the Vavr library in Java. The Try class is a functional programming construct for handling computations that may succeed or fail. It encapsulates exceptions and streamlines error handling, reducing boiler

Downloads

380

Readme

Try-Typescript

You can find this library on NPM: Try-Typescript

Overview

This repository contains an implementation of the Try class, inspired by the Vavr library in Java. The Try class is a functional programming construct designed to handle computations that may result in success or failure. It allows developers to encapsulate exceptions and manage error handling in a more functional and expressive manner, reducing boilerplate code and improving code readability.

Features

  • Functional Methods: Includes a variety of methods that allow for functional transformations and error recovery:

    • Mapping: Transform the result of a successful computation using map and flatMap.
    • Error Recovery: Recover from failures using recover and recoverWith methods.
    • Conditional Execution: Filter results with filter and execute side effects with onSuccess and onFailure.
  • Custom Exception Handling: Provides mechanisms to specify custom behavior for both success and failure cases, enabling tailored error handling strategies.

Available functions

Initialization functions

of<T>(fn: () => T): Try<T>

Creates a Try instance from a function that may throw an error.

const of = await Try.of(() => {
  if (Math.random() > 0.5) {
    return 10;
  } else {
    throw new Error('An error occurred');
  }
}).get(); // => 10 or throws 'An error occurred'

combine<T extends any[], R>(...args: [...{ [K in keyof T]: Try<T[K]> }, (...values: T) => R]): Try<R>

Sometimes you may want to combine multiple Try instances into one. This function allows you to do that. It takes multiple Try instances and a function that will be executed if all Try instances are successful. If one of the Try instances is a failure, the function will not be executed and the resulting Try instance will be a failure.

//All passed Try instances are successful
const r = Try.success(2);
const r2 = Try.success(3);
const r3 = Try.of(() => {
  if(0.6 > 0.5) return "3";
  throw new Error("Random error");
});

const f = (a: number, b: number, c: string) => a + b + c;

const r4 = await Try.combine(r, r2, r3, f).get(); //=> "53" ;

//One of the passed Try instances is a failure
const r = Try.success(2);
const r2 = Try.success(3);
const r3 = Try.of(() => {
  if(0.3 > 0.5) return "3";
  throw new Error("Random error");
}); //=> Is a Failure


const f = (a: number, b: number, c: string) => a + b + c;

const r4 = Try.combine(r, r2, r3, f);

await r4.get(); //=> Will throw 'Random error'

success<T>(value: T): Try<T>

Creates a Try instance with a successful value.

const success = await Try.success(10).get(); // => 10

failure<T>(error: Error): Try<T>

Creates a Try instance with a failure value.

const failure = await Try.failure(new Error('An error occurred')).get(); // => Will throw 'An error occurred'

Execution functions

This library will not run chained methods when they are called inside your code. You need to call a so called execution method to start executing the methods chain. This is necessary because of the nature of promises. Execution methods are async because they will run the async functions provided to chaining methods like map, recover, ... If you just want to run the Try instance method chain without returning any value, you can use the run method. If you want to get the value of the Try instance, you can use the get method.

To give you an example, let's say you have a Try instance like below:

const tryInstance = Try.success(10)
    .map(v => v + 1)
    .filter(v => v > 5)
    .recover(() => 0);

If you want to get the value of the computation of all methods, you can use the get method like below:

const value = await tryInstance.get(); // => 11

Internally get will run all the methods in the chain: map, filter, recover and return the value of the Try instance. If you want to run the methods chain without getting the value, you can use the run method like below:

await tryInstance.run(); // => Will run all the functions in the chain without returning the value.

get(): Promise<T>

Gets the value of the Try instance. If the Try instance is a Failure, it will throw the error. Due to the nature of this library and potential asynchronous methods passed to transformation methods, it is necessary to await the result of this function.

//Sucess
const value = await Try.success(10).get(); // => 10

//Failure
const failure = await Try.failure(new Error('An error occurred')).get(); // => Will throw 'An error occurred'

run(): Promise<Try<T>>

Runs the Try instance and returns the Try instance itself. This is executing a Try instance if no returned value is expected. Due to the nature of this library and potential asynchronous operations passed to transformation methods, it is necessary to await the result of this function.

//Success
const sucess = await Try.success(10).run(); // => Try instance with calculated value 10

//Failure
const failure = await Try.failure(new Error('An error occurred')).run(); // => Try instance with error 'An error occurred'

//Useful case
await Try.success(1)
        .filter(v => v > 2, v => { throw new Error("Custom Predicate does not hold for " + v)})
        .run(); //Will throw the custom error

getOrElse<U>(defaultValue: U): Promise<U | T>

Returns the value of the Try instance if it is a Success, otherwise returns the default value. Due to the nature of this library and potential asynchronous operations passed to transformation methods, it is necessary to await the result of this function.

//Success
const value = await Try.success(10).getOrElse(0); // => 10

//Failure
const failure = await Try.failure(new Error('An error occurred')).getOrElse(0); // => 0

getOrElseGet<U>(fn: (ex: Error) => U): Promise<T | U>

Returns the value of the Try instance if it is a Success, otherwise returns the value returned by the function.

//Success
const value = await Try.success(10).getOrElseGet(() => 0); // => 10

//Failure
const failure = await Try.failure(new Error('An error occurred')).getOrElseGet(() => 0); // => 0

getOrElseThrow<U>(fn: (error: Error) => U): Promise<T | U>

Returns the value of the Try instance if it is a Success, otherwise throws the error returned by the function.

//Success
const value = await Try.success(10).getOrElseThrow(() => new Error('An error occurred')); // => 10

//Failure
const failure = await Try.failure(new Error('An error occurred')).getOrElseThrow(() => new Error('Another error occurred')); // => Will throw 'Another error occurred'

Other functions

isSuccess(): boolean

Returns true if the Try instance is a Success, otherwise returns false.

//Success
const success = Try.success(10).isSuccess(); // => true

//Failure
const failure = Try.failure(new Error('An error occurred')).run().isSuccess(); // => false

isFailure(): boolean

Returns true if the Try instance is a Failure, otherwise returns false.

//Success
const success = Try.success(10).isFailure(); // => false

//Failure
const failure = Try.failure(new Error('An error occurred')).run().isFailure(); // => true

map<U>(fn: (value: T) => U): Try<U>

Maps the value of the Try instance if it is a Success, otherwise returns the Failure instance.

//Success
const value = await Try.success(10)
        .map(v => v + 1)
        .get(); // => 11

//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .map(v => v + 1)
        .get(); // => Will throw 'An error occurred'

flatMap<U>(fn: (value: T) => Try<U>) : Try<U>

Maps the value of the Try instance if it is a Success, otherwise returns the Failure instance.

//Success
const value = await Try.success(10)
        .flatMap(v => Try.success(v + 1))
        .get(); // => 11

//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .flatMap(v => Try.success(v + 1))
        .get(); // => Will throw 'An error occurred'

mapFailure<E extends Error, U extends Error>(func: (ex: E) => U | Promise<U>): Try<T>

Maps a failure of the Try instance if it is a Failure, otherwise returns the Success instance.

class CustomException extends Error {
  constructor(message: string) {
    super(message);
    this.name = "CustomException";
  }
}

class MappedCustomException extends Error {
  cause: string;
  constructor(message: string, cause: string) {
    super(message);
    this.cause = cause;
    this.name = "MappedCustomException";
  }
}

test("Try.mapFailure should map an instance of CustomException to MappedCustomException", async () => {
  const result = Try.failure(new CustomException("This is a test!"))
          .mapFailure(async (_)=> new MappedCustomException("Mapped Custom Exception", "Custom Exception"));
  await expect(result.get()).rejects.toThrow(MappedCustomException);
  expect(result.isSuccess()).toBe(false);
});

mapFailureWith<E extends Error, U extends Error>(errorType: new (...args: any[]) => E, func: (ex: E) => U | Promise<U>): Try<T>

Maps a failure of the Try instance if it is a specific error type using a function provided with the previous error if it is a Failure, otherwise returns the Success instance.

class CustomException extends Error {
  constructor(message: string) {
    super(message);
    this.name = "CustomException";
  }
}

class MappedCustomException extends Error {
  cause: string;
  constructor(message: string, cause: string) {
    super(message);
    this.cause = cause;
    this.name = "MappedCustomException";
  }
}

test("Try.mapFailureWith should map an instance of CustomException to MappedCustomException", async () => {
  const result = Try.failure(new CustomException("This is a test!"))
          .mapFailureWith(CustomException, async (err) => {
            return new MappedCustomException("Mapped Custom Exception", err.message);
          });
  await expect(result.get()).rejects.toThrow(MappedCustomException);
  expect(result.isSuccess()).toBe(false);
});

recover<U>(fn: (error: Error) => U): Try<T | U>

Recovers the value of the Try instance if it is a Failure, otherwise returns the Success instance.

//Success
const value = await Try.success(10)
        .recover(() => 0)
        .get(); // => 10
        
//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .recover(() => 0)
        .get(); // => 0

recoverWith<U>(fn: (error: Error) => Try<U>): Try<U | T>

Recovers the value of the Try instance if it is a Failure, otherwise returns the Success instance.

//Success
const value = await Try.success(10)
        .recoverWith(() => Try.success(0))
        .get(); // => 10
        
//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .recoverWith(() => Try.success(0))
        .get(); // => 0

andThen(fn: (value: T) => any): Try<T>

Runs the function if the Try instance is a Success.

//Success
const value = await Try.success(10)
        .andThen(v => console.log(v)) // => Will print 10
        .get(); // => 10

//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .andThen(v => console.log(v)) // => Will print nothing
        .get(); // => Will throw 'An error occurred'

filter(predicateFunc: (value: T) => boolean, throwbackFunction?: (value: T) => void): Try<T>

Filters the value of the Try instance if it is a Success, otherwise returns the Failure instance.

//Success
const value = await Try.success(10)
        .filter(v => v > 5)
        .get(); // => 10
        
//Failure
const failure = await Try.success(10)
        .filter(v => v > 15)
        .get(); // => Will throw 'Predicate does not hold for 10'

//Failure with custom error
const failureWithCustomError = await Try.success(10)
        .filter(v => v > 15, v => { throw new Error("Custom Predicate does not hold for " + v)})
        .get(); // => Will throw 'Custom Predicate does not hold for 10'

filterNot(predicateFunc: (value: T) => boolean, throwbackFunction?: (value: T) => void): Try<T>

Filters the value of the Try instance if it is a Success, otherwise returns the Failure instance.

//Success
const value = await Try.success(10)
        .filterNot(v => v > 15)
        .get(); // => 10
        
//Failure
const failure = await Try.success(10)
        .filterNot(v => v > 5)
        .get(); // => Will throw 'Predicate holds for 10'

//Failure with custom error
const failureWithCustomException = await Try.success(10)
        .filterNot(v => v > 5, v => { throw new Error("Custom Predicate holds for " + v)})
        .get(); // => Will throw 'Custom Predicate holds for 10'

onFailure(fn: (ex: Error) => void): Try<T>

Runs the function if the Try instance is a Failure.

//Success
const value = await Try.success(10)
        .onFailure(ex => console.log(ex)) // => Will not print
        .get(); // => 10
        
//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .onFailure(ex => console.log(ex)) // => Will print 'An error occurred'
        .run(); 

onSuccess(fn: (value: T) => void): Try<T>

Runs the function if the Try instance is a Success.

//Success
const value = await Try.success(10)
        .onSuccess(v => console.log(v)) // => Will print 10
        .get(); // => 10
        
        
//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .onSuccess(v => console.log(v)) // => Will not print
        .get(); // => Will throw 'An error occurred'

getCause(): Error | undefined

Returns the error of the Try instance if it is a Failure, otherwise returns undefined.

//Success
const value = (await Try.success(10).run()).getCause(); // => undefined

//Failure
const failure = Try.failure(new Error('An error occurred')).getCause(); // => Error('An error occurred')

peek(fn: (value: T) => void): Try<T>

Peeks the value of the Try instance if it is a Success, otherwise returns the Failure instance.

//Success
const value = await Try.success(10)
        .peek(v => console.log(v)) // => Will print 10
        .get(); // => 10

//Failure
const failure = await Try.failure(new Error('An error occurred'))
        .peek(v => console.log(v)) // => Will not print
        .get(); // => Will throw 'An error occurred'