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

@ryanxcharles/result

v1.0.3

Published

A Rust-like Result type for TypeScript/node.js/deno/bun.

Downloads

78

Readme

@ryanxcharles/result

This repository provides a set of utility functions and types to work with results in TypeScript. It follows the Result type pattern commonly seen in languages like Rust, allowing functions to return either a successful result (Ok) or an error (Err) without throwing exceptions. This makes error handling more predictable and functional.

Features

  • Result Type: A Result type that represents either a success (Ok) or failure (Err).
  • Utility Functions:
    • Ok: Creates a successful result.
    • Err: Creates an error result.
    • isOk: Type guard to check if a result is successful.
    • isErr: Type guard to check if a result is an error.
  • Async and Sync Result Wrappers:
    • asyncResult: Wraps a promise, capturing success or error as a Result type.
    • syncResult: Wraps a function call, capturing success or error as a Result type.

Installation

With npm:

npm install @ryanxcharles/result

With pnpm:

pnpm install @ryanxcharles/result

Usage

Here's how you can use the Result type and utility functions.

Basic Usage

import {
  Ok,
  Err,
  isOk,
  isErr,
  asyncResult,
  syncResult,
} from "@ryanxcharles/result";

// Create a successful result
const success = Ok("Data loaded successfully");
console.log(success); // { value: 'Data loaded successfully', error: null }

// Create an error result
const error = Err("Failed to load data");
console.log(error); // { value: null, error: 'Failed to load data' }

// Checking result types
if (isOk(success)) {
  console.log("Success:", success.value);
} else if (isErr(error)) {
  console.log("Error:", error.error);
}

Using asyncResult for Promises

Wrap a promise to handle success or error without using try-catch:

const loadData = async () => {
  const result = await asyncResult(fetchData());
  if (isOk(result)) {
    console.log("Data:", result.value);
  } else {
    console.log("Error:", result.error);
  }
};

Using syncResult for Function Calls

Wrap a function call to handle success or error without using try-catch:

const calculate = (a: number, b: number) => a + b;
const result = syncResult(calculate, 1, 2);

if (isOk(result)) {
  console.log("Calculation Result:", result.value);
} else {
  console.log("Error:", result.error);
}

Working with the Result Type

The Result type provides a way to return either a successful result (Ok) or an error (Err) from a function without using exceptions. This can make functions more predictable and help ensure that error handling is explicit.

Defining Functions that Return a Result Type

To define a function that returns a Result, determine the types for the success and error values and use the Ok and Err utility functions to return results accordingly.

Example: Basic Function Returning a Result Type

Let’s create a function parseNumber that takes a string and tries to convert it to a number. If the string cannot be parsed, it returns an Err with an error message; otherwise, it returns an Ok with the parsed number.

import type { Result } from "@ryanxcharles/result";
import { Ok, Err, isOk, isErr } from "@ryanxcharles/result";

function parseNumber(value: string): Result<number, string> {
  const parsed = Number(value);
  if (isNaN(parsed)) {
    return Err(`"${value}" is not a valid number`);
  }
  return Ok(parsed);
}

// Usage
const result = parseNumber("42");
if (isOk(result)) {
  console.log("Parsed number:", result.value); // Output: Parsed number: 42
} else {
  console.log("Error:", result.error);
}

Using Result for Error Handling in Asynchronous Functions

Here’s an example of an asynchronous function that fetches data and returns a Result type. The function will return Ok with the fetched data if successful, or Err with an error message if an error occurs.

async function fetchData(url: string): Promise<Result<string, string>> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      return Err(`Failed to fetch data: ${response.statusText}`);
    }
    const data = await response.text();
    return Ok(data);
  } catch (error: unknown) {
    if (error instanceof Error) {
      return Err(error.message);
    }
    return Err("An unknown error occurred");
  }
}

// Usage
const result = await fetchData("https://api.example.com/data");
if (isOk(result)) {
  console.log("Fetched data:", result.value);
} else {
  console.log("Error:", result.error);
}

Propagating Result in a Chain of Functions

When working with multiple functions that return a Result, you can propagate errors easily by returning Err without further processing or returning Ok if all steps are successful. Here’s an example:

function validateNumber(value: number): Result<number, string> {
  if (value < 0) {
    return Err("Number must be non-negative");
  }
  return Ok(value);
}

function doubleNumber(value: number): Result<number, string> {
  return Ok(value * 2);
}

function processNumber(value: string): Result<number, string> {
  const parsed = parseNumber(value);
  if (isErr(parsed)) return parsed;

  const validated = validateNumber(parsed.value);
  if (isErr(validated)) return validated;

  return doubleNumber(validated.value);
}

// Usage
const result = processNumber("42");
if (isOk(result)) {
  console.log("Processed number:", result.value); // Output: Processed number: 84
} else {
  console.log("Error:", result.error);
}

In this example:

  1. parseNumber converts the string to a number.
  2. validateNumber checks if the number is non-negative.
  3. doubleNumber doubles the number if all previous steps succeeded.

Each function call checks for errors using isErr and returns an Err result if any step fails, making error handling straightforward and eliminating the need for exceptions.

Summary

Using Result makes error handling in TypeScript more functional and explicit by:

  • Encouraging the use of Ok and Err to signal success or failure.
  • Providing isOk and isErr type guards for easy inspection.
  • Enabling simple propagation of errors without throwing exceptions.

This approach can make your codebase easier to understand and maintain, as errors are handled in a predictable and consistent way.

Testing

This project uses Vitest for testing. To run the tests, use the following command:

pnpm run test

Running Specific Tests

To run specific tests, you can use Vitest’s filtering options:

pnpm run test <test-name>

Contributing

Contributions are welcome! If you’d like to improve or extend this library, please fork the repository and submit a pull request.

  1. Fork the repo.
  2. Create a new branch (git checkout -b feature/your-feature).
  3. Make your changes.
  4. Commit your changes (git commit -am 'Add some feature').
  5. Push to the branch (git push origin feature/your-feature).
  6. Open a pull request.

License

This project is licensed under the MIT License. See the LICENSE file for details.