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

@hulla/control

v0.0.3

Published

A TypeScript library for functional error handling using the Result pattern. This library provides a robust and type-safe way to handle errors without throwing exceptions, making error handling more predictable and easier to reason about.

Downloads

5

Readme

@hulla/control

A TypeScript library for functional error handling using the Result pattern. This library provides a robust and type-safe way to handle errors without throwing exceptions, making error handling more predictable and easier to reason about.

Features

  • 🎯 Type-safe error handling with Result<T, E> type
  • 🔄 Functional approach with pattern matching
  • ⚡ Support for both synchronous and asynchronous operations
  • 🏷️ Custom tagging for better error categorization
  • 🔍 Comprehensive TypeScript type definitions
  • 🧪 Well-tested and production-ready

Installation

Node.js

# Using npm
npm install @hulla/control

# Using yarn
yarn add @hulla/control

# Using pnpm
pnpm add @hulla/control

# Using bun
bun add @hulla/control

Deno

import { ok, err, type Result } from "npm:@hulla/control"

Or add it to your deno.json:

{
  "imports": {
    "@hulla/control": "npm:@hulla/control"
  }
}

Usage

Basic Usage

import { ok, err, type Result } from '@hulla/control'

interface User {
  id: string
  name: string
  age: number
}

function checkAge(user: User) {
   if (user.age < 18) {
      return err(new Error("You must be at least 18 to enter"))
   }
   return ok(user)
}

const checkedUser = checkAge(20) // Ok<User> | Err<Error>

// Type safe handling
if (checkedUser.isOk()) {
  const user = checkedUser.value
  console.log(`User ${user.name}, ${user.email}`)
} else {
  // Can also use isErr instead of isOk
  const message = checkedUser.error
  console.error(error)
}

// Use result pattern matching (rust-like) 🦀
checkedUser.match(
  user => console.log(`User ${user.name}, ${user.email}`)
  error => console.error(error.message)
)

// Or pair handling (go-like) 🦫🌀
const [user, error] = checkedUser.pair()
if (error) // ...
if (user) // ...

Handling error-prone functions/values

Not sure about an external library potentially throwing an error you have no control over?

Using tcf - typed version of Try-Catch-Finally

import { tcf } from '@hulla/control'
import { doSomething } form 'some-external-library'

async function safeDoSomething(path: string) {
  return tcf({
    try: () => {
      return doSomething(path) // -> string
    },
    // can also be a other (custom) error type instead of just Error
    catch: (error: Error) => new Error( // must return an error
      `Failed to read ${path}: ${error.message}`
    ),
    finally: () => console.log('File operation completed') // optional
  })
}

const result = safeDoSomething('package.json') // Ok<string> | Err<Error>

// Rest of error/value handling like in the example above ^

Using result

Alternatively, if you know the code and know it will only return error/value type, i.e. string | Error you can use result to conver it to Ok<string> | Err<Error> type.

import { result } from '@hulla/control'

const valueOrError = doSomething() // string | Error
const converted = result(valueOrError) // Ok<string> | Err<Error>

Async Operations

const asyncResult = ok(Promise.resolve(42))

// Pattern matching preserves Promise
const doubled = await asyncResult.match(
  async value => value * 2,
  error => 0
)

// Pair method also handles Promises
const [value, error] = await asyncResult.pair()

Result Tagging

Tagging allows you to add semantic meaning to your results, making it easier to categorize and handle different types of successes and errors. This is particularly useful when you need to:

  1. Distinguish between different types of errors (e.g., validation, network, auth)
  2. Categorize successful operations (e.g., created, updated, cached)
  3. Build type-safe error handling flows
import { ok, err, tcf, type Result } from '@hulla/control'

// Basic tagging
const success = ok("Data loaded", "FETCH_SUCCESS")
const failure = err(new Error("Network error"), "NETWORK_ERROR")

// Tagged results in functions
function validateUser(data: unknown): Result<User, Error> {
  return tcf({
    try: () => {
      if (!data.name) throw new Error("Name required")
      return data as User
    },
    catch: (error: Error) => error,
    tagOk: "VALIDATION_SUCCESS",
    tagError: "VALIDATION_ERROR"
  })
}

// Type-safe handling based on tags
const result = validateUser(data)
if (result.isErr() && result.tag === "VALIDATION_ERROR") {
  // Handle validation errors specifically
  showValidationError(result.error)
}

// Tagging with tcf wrapper
function fetchUserData(id: string) {
  return tcf({
    try: () => api.getUser(id),
    catch: (error: Error) => error,
    tagOk: "USER_FOUND",
    tagError: "USER_NOT_FOUND",
    finally: () => console.log("Fetch completed")
  })
}

// Pattern matching with tagged results
const userResult = await fetchUserData("123")
userResult.match(
  user => {
    if (userResult.tag === "USER_FOUND") {
      updateUI(user)
    }
    // ...
  },
  error => {
    if (userResult.tag === "USER_NOT_FOUND") {
      showNotFoundError()
    }
    // ....
  }
)

API Reference

Types

  • Result<T, E> - Main result type that can be either Ok<T> or Err<E>
  • Ok<T> - Success type containing a value of type T
  • Err<E> - Error type containing an error of type E
  • Tagged<T, Tag> - Result type with custom string tag

Functions

  • ok<T>(value: T): Ok<T> - Create a success result
  • err<E>(error: E): Err<E> - Create an error result
  • tcf(options) - Functional try-catch-finally wrapper
  • result(value, config?) - Create a Result from a value that might be an error

Methods

Each Result instance provides:

  • isOk() - Type guard for success case
  • isErr() - Type guard for error case
  • match(okFn, errFn) - Pattern matching
  • pair() - Convert to [value, error] tuple
  • unwrap() - Get raw value/error

License

MIT License - see the LICENSE file for details.

Author

Samuel Hulla (@samuelhulla)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.