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

@ts-fns/stdlib

v0.2.1

Published

A Functional Programming Standard Library for Typescript

Readme

@ts-fns/stdlib

Core concepts

  • Functional Programming style API
  • Stand-alone functions
  • Fully type-safe
  • Immutability, with appropriate exceptions
  • Normalized return types to Error | T unions
  • pipe/compose work like ADT map/flatMap under the hood
  • Interoperable with other FP focused libraries!

Elixir style everything, for consistent, clean, and type-safe code

Usage

Very much a Work in progress

Still working on the standard alias

import * as Arr from '@ts-fns/stdlib/array';
import * as Func from '@ts-fns/stdlib/function';
import * as Guard from '@ts-fns/stdlib/guard';
import * as Iter from '@ts-fns/stdlib/iterator';
import * as Lens from '@ts-fns/stdlib/lens';
import * as Map from '@ts-fns/stdlib/map';
import * as Num from '@ts-fns/stdlib/number';
import * as Obj from '@ts-fns/stdlib/object';
import * as Ord from '@ts-fns/stdlib/order';
import * as Set from '@ts-fns/stdlib/set';
import * as Str from '@ts-fns/stdlib/string';
import * as Tuple from '@ts-fns/stdlib/tuple';

Details

Normalized return types to Error | T unions

Javascript has no normalized "Empty" value that gets returned from methods. -1? undefined? null?. In addition, while exceptions and try/catch blocks are the built-in mechanisms for Errors, sometimes those errors are represented as values. For example, Number.parseInt() returns NaN instead of throwing.

Errors-as-values in the form of unions are the most idiomatic way to continue to use javascript without introducing new paradigms such as Result. Control-flow logic doesn't change in most cases, you just change your condition parameters

/* vanilla js */
const user = users.find(u => u.id === id);
//    ^? User | undefined

if (user === undefined) {
  // handle "NotFound" case
}

/* @ts-fns/stdlib */
import * as Arr from '@ts-fns/stdlib/array';

const user = Arr.find(users, u => u.id === id);
//    ^? User | NotFoundError

if (user instanceof NotFoundError) {
  // handle "NotFound" case
}

While functions that throw get changed from try-catch blocks to other control-flow mechanics, this is probably for the better, as it aligns into a single paradigm flow

/* vanilla js */
let updatedUsers;
try {
  updatedUsers = users.with(5, updatedUser);
} catch(e) {
  // handle error
}

/* @ts-fns/stdlib */
import * as Arr from '@ts-fns/stdlib/array';

const updatedUsers = Arr.insert(users, 5, updatedUser)

if (updatedUsers instanceof RangeError) {
  // handle error
}

Errors are no longer opaque, and compliment Typescript's type system. Yielding more type-safety and less error prone code.

Two Type of Errors

This repo subscribes to Effect's philosophy that there are Expected and Unexpected Errors (read about it here: https://effect.website/docs/guide/effects/errors).

Just like Effect does not track Unexpected Errors, neither does @ts-fns/stdlib. In particular, this library only captures expected errors, returning them as values. Unexpected errors are thrown as normal.

Expected Errors

Some examples

  • Array.prototype.with() throws a RangeError if the index is out of bounds. Arr.update() returns RangeError as a value for the same reason.
  • Different value are used to represent "not found". Arr.indexOf() returns -1. Arr.find() returns undefined. Str.match() returns null. @ts-fns/stdlib normalizes these by returning NotFoundError as a value
  • Array function that would normally return when called on an empty array will return EmptyArrayError instead.

All functions that catch, or add, expected Errors will return that errors as a value, typed as part of that function's return type union.

Type narrowing to remove errors from return type

Arr.first() returns EmptyArrayError | T. The guard function Arr.isNotEmpty() validates at runtime that an array is not empty and narrow an array T[] to NonEmptyArray<T>. Arr.first() is typed to accept ReadonlyNonEmptyArray<T> and will return only T for that case. This allows you to remove errors from the return type by validating at runtime that the error condition cannot exist.

import * as Arr from '@ts-fns/stdlib/array';

const arr: number[] = [];

const first = Arr.first(arr);
//    ^? EmptyArrayError | number

if (Arr.isNotEmpty(arr)) {
  const first = Arr.first(arr);
  //    ^? number
}

Unexpected Errors

Str.startsWith() is a good example. Javascript's String.prototype.startsWith() throws an TypeError if the search value is a regex. Though defined, this error is considered unexpected because it would be illogical to use a regex. Javascript coerces other types to strings, Typescript defines string as the only valid argument type.

Any function that does this will have @throws in their JSDoc comment to indicate this possibility.

TODO

Go over:

  • .assert() to remove errors from the return types but with the risk of throwing
  • gen() function to utilize generator functions to write procedural code and aggregate error handle to the result
  • pipe/compose act like ADT .map()/.flatMap() under-the-hood, allowing you to string together functions that throw error, but defer those errors to the result