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 🙏

© 2026 – Pkg Stats / Ryan Hefner

happy-rusty

v1.8.0

Published

Rust's Option, Result, and sync primitives for JavaScript/TypeScript - Better error handling and null-safety patterns.

Readme

happy-rusty

License Build Status codecov NPM version NPM downloads JSR Version JSR Score

Rust's Option, Result, and sync primitives for JavaScript/TypeScript - Better error handling and null-safety patterns.


中文 | API Documentation


Features

  • Option<T> - Represents an optional value: every Option is either Some(T) or None
  • Result<T, E> - Represents either success (Ok(T)) or failure (Err(E))
  • Sync Primitives - Rust-inspired Once<T>, OnceAsync<T>, Lazy<T>, LazyAsync<T>, Mutex<T>, RwLock<T>, and Channel<T>
  • Control Flow - ControlFlow<B, C> with Break and Continue for short-circuiting operations
  • FnOnce - One-time callable function wrappers (FnOnce and FnOnceAsync)
  • Full TypeScript support with strict type inference
  • Async support - Async versions of all transformation methods
  • Zero dependencies
  • Runtime immutability - All instances are frozen with Object.freeze()
  • Cross-runtime - Works in Node.js, Deno, Bun, and browsers

Installation

# npm
npm install happy-rusty

# yarn
yarn add happy-rusty

# pnpm
pnpm add happy-rusty

# JSR (Deno)
deno add @happy-js/happy-rusty

# JSR (Bun)
bunx jsr add @happy-js/happy-rusty

Quick Start

import { Some, None, Ok, Err } from 'happy-rusty';

// Option - handling nullable values
function findUser(id: number): Option<User> {
    const user = database.get(id);
    return user ? Some(user) : None;
}

const user = findUser(1)
    .map(u => u.name)
    .unwrapOr('Guest');

// Result - handling errors
function parseJSON<T>(json: string): Result<T, Error> {
    try {
        return Ok(JSON.parse(json));
    } catch (e) {
        return Err(e as Error);
    }
}

const config = parseJSON<Config>(jsonStr)
    .map(c => c.settings)
    .unwrapOrElse(err => {
        console.error('Parse failed:', err);
        return defaultSettings;
    });

API Overview

Option<T>

| Category | Methods | |----------|---------| | Constructors | Some(value), None | | Querying | isSome(), isNone(), isSomeAnd(fn) | | Extracting | expect(msg), unwrap(), unwrapOr(default), unwrapOrElse(fn) | | Transforming | map(fn), mapOr(default, fn), mapOrElse(defaultFn, fn), filter(fn), flatten() | | Boolean ops | and(other), andThen(fn), or(other), orElse(fn), xor(other) | | Converting | okOr(err), okOrElse(fn), transpose() | | Combining | zip(other), zipWith(other, fn), unzip() | | Side effects | inspect(fn) | | Comparison | eq(other) |

Result<T, E>

| Category | Methods | |----------|---------| | Constructors | Ok(value), Ok() (void), Err(error) | | Querying | isOk(), isErr(), isOkAnd(fn), isErrAnd(fn) | | Extracting Ok | expect(msg), unwrap(), unwrapOr(default), unwrapOrElse(fn) | | Extracting Err | expectErr(msg), unwrapErr() | | Transforming | map(fn), mapErr(fn), mapOr(default, fn), mapOrElse(defaultFn, fn), flatten() | | Boolean ops | and(other), andThen(fn), or(other), orElse(fn) | | Converting | ok(), err(), transpose() | | Type casting | asOk<F>(), asErr<U>() | | Side effects | inspect(fn), inspectErr(fn) | | Comparison | eq(other) |

Async Methods

All transformation methods have async variants with Async suffix (e.g., andThenAsync, mapAsync, unwrapOrElseAsync).

Type Aliases

type AsyncOption<T> = Promise<Option<T>>;
type AsyncResult<T, E> = Promise<Result<T, E>>;
type IOResult<T> = Result<T, Error>;          // For I/O operations
type AsyncIOResult<T> = Promise<IOResult<T>>; // Async I/O operations

Utility Functions

import { tryResult, tryAsyncResult } from 'happy-rusty';

// Capture exceptions as Result (like Promise.try, but returns Result)
const parsed = tryResult(JSON.parse, jsonString);  // Ok(value) or Err(error)
const response = await tryAsyncResult(fetch, '/api/data');

Sync Primitives

import { Lazy, LazyAsync, Mutex, Channel } from 'happy-rusty';

// Lazy - compute once on first access
const expensive = Lazy(() => computeExpensiveValue());
expensive.force();  // Computed once, cached thereafter

// LazyAsync - async lazy initialization (concurrent-safe)
const db = LazyAsync(async () => Database.connect(url));
await db.force();  // Only one connection, concurrent calls wait

// Mutex - async mutual exclusion
const state = Mutex({ count: 0 });
await state.withLock(async (s) => { s.count += 1; });

// Channel - MPMC async message passing
const ch = Channel<string>(10);  // bounded capacity
await ch.send('hello');
for await (const msg of ch) { console.log(msg); }

Examples

Design Notes

Immutability

All types (Option, Result, ControlFlow, Lazy, LazyAsync, Once, OnceAsync, Mutex, MutexGuard, RwLock, Channel, Sender, Receiver, FnOnce, FnOnceAsync) are immutable at runtime via Object.freeze(). This prevents accidental modification of methods or properties:

const some = Some(42);
some.unwrap = () => 0;  // TypeError: Cannot assign to read only property

Why no readonly in TypeScript interfaces?

We intentionally omit readonly modifiers from method signatures in interfaces. While this might seem to reduce type safety, there are compelling reasons:

  1. Inheritance compatibility - The None type extends Option<never>. TypeScript's arrow function property syntax (readonly prop: () => T) uses contravariant parameter checking, which causes None (with never parameters) to be incompatible with Option<T>. Method syntax (method(): T) uses bivariant checking, allowing the inheritance to work correctly.

  2. Runtime protection is sufficient - Object.freeze() already prevents reassignment at runtime. Adding readonly only provides compile-time checking, which offers marginal benefit when runtime protection exists.

  3. Cleaner API - Avoiding the Mutable* + Readonly<> pattern keeps the exported types clean and documentation readable.

  4. Testing validates immutability - Our test suite explicitly verifies that all instances are frozen and reject property modifications.

Why happy-rusty?

JavaScript's null/undefined and try-catch patterns lead to:

  • Uncaught null reference errors
  • Forgotten error handling
  • Verbose try-catch blocks
  • Unclear function contracts

happy-rusty provides Rust's battle-tested patterns:

  • Explicit optionality - Option<T> makes absence visible in types
  • Explicit errors - Result<T, E> forces error handling consideration
  • Method chaining - Transform values without nested if-else or try-catch
  • Type safety - Full TypeScript support with strict type inference

License

MIT