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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@mvst/ts-unions

v0.5.0

Published

TypeScript union types for Maybe and RemoteData with pattern matching

Readme

ts-unions

TypeScript union types for Maybe and RemoteData with pattern matching.

npm version License: MIT

Installation

npm install @mvst/ts-unions

Usage

Maybe Type

The Maybe type represents a value that might or might not exist. It's useful for handling nullable values in a type-safe way.

import { Maybe, M } from "@mvst/ts-unions";

// Creating Maybe values
const someValue: Maybe<number> = M.just(42);
const noValue: Maybe<number> = M.nothing();

// Pattern matching
M.when(someValue, {
  just: (value) => `Value is ${value}`,
  nothing: () => "No value"
});

M.when(someValue, {
  _: () => "This is the fallack case"
});


// Transforming values
const doubled: Maybe<number> = M.map((x) => x * 2, someValue);

// Chaining operations
const chained: Maybe<number> = M.andThen((x) => M.just(x + 1), someValue);

// Unwrapping values
const value: number = M.withDefault(0, someValue); // Unwraps the value or returns 0 if nothing

Maybe API

  • M.just(value: T): Maybe<T> - Creates a Maybe with a value
  • M.nothing(): Maybe<T> - Creates a Maybe without a value
  • M.when(pattern: Pattern , maybe: Maybe<T>): R - Pattern matching
  • M.map(fn: (value: T) => R, maybe: Maybe<T>): Maybe<R> - Transform the value if it exists
  • M.andThen(fn: (value: T) => Maybe<R>, maybe: Maybe<T>): Maybe<R> - Chain Maybe operations
  • M.isJust(maybe: Maybe<T>): boolean - Check if Maybe has a value
  • M.isNothing(maybe: Maybe<T>): boolean - Check if Maybe has no value

RemoteData Type

The RemoteData type represents the state of a remote data operation. It's perfect for handling API calls and async operations.

import { RemoteData, RD } from "@mvst/ts-unions";

// Creating RemoteData values
const data: RemoteData<string> = RD.notAsked();
const loadingData: RemoteData<string> = RD.loading();
const successData: RemoteData<string> = RD.success("Data loaded");
const errorData: RemoteData<string> = RD.error(new Error("Failed to load"));

// Pattern matching
RD.when(data, {
  notAsked: () => "Not started",
  loading: () => "Loading...",
  success: (value) => `Data: ${value}`,
  error: (err) => `Error: ${err.message}`
});

RD.when(data, {
  success: (value) => `Data: ${value}`,
  _: () => "This is the fallback case, all other cases are handled here"
});

// Transforming values
const transformed = RD.map((value) => value.toUpperCase(), successData);

// Chaining operations
const chained = RD.andThen((value) => RD.success(value + "!!!"), successData);

// Unwrapping values
const unwrapped = RD.withDefault("No data", successData); // Unwraps the value or returns "No data" if not success

RemoteData API

  • RD.notAsked(): RemoteData<T> - Initial state
  • RD.loading(): RemoteData<T> - Loading state
  • RD.success(value: T): RemoteData<T> - Success state with value
  • RD.error(error: Error): RemoteData<T> - Error state with error
  • RD.when(pattern: Pattern, data: RemoteData<T>): R - Pattern matching
  • RD.map(fn: (value: T) => R, data: RemoteData<T>): RemoteData<R> - Transform success value
  • RD.andThen(fn: (value: T) => RemoteData<R>, data: RemoteData<T>): RemoteData<R> - Chain RemoteData operations
  • RD.isNotAsked(data: RemoteData<T>): boolean - Check if not asked
  • RD.isLoading(data: RemoteData<T>): boolean - Check if loading
  • RD.isSuccess(data: RemoteData<T>): boolean - Check if success
  • RD.isError(data: RemoteData<T>): boolean - Check if error

Features

  • The library is tree-shakable
  • All the values are immutable and that operations like map and andThen never modify the original value.
  • All the values are serializable (e.g.: you can easily store them in local storage or send them over the network).
  • All the functions in the libray are curried, so you can partially apply them and create reusable functions.

Currying and Composition

This makes it easy to create reusable functions and compose them together. The library also provides compose and pipe utilities to help with function composition, although you might already have access to similar functions if you're using any functional programming library.

Currying Examples

Maybe

import { Maybe, M } from "@mvst/ts-unions";

// Create reusable functions by partially applying map
const double = M.map((x: number) => x * 2);
const addOne = M.map((x: number) => x + 1);

// Use them with different Maybe values
const value1 = M.just(42);
const value2 = M.just(10);

const doubled1 = double(value1); // Just(84)
const doubled2 = double(value2); // Just(20)

// Compose functions using pipe
const doubleAndAddOne = pipe(double, addOne);
const result = doubleAndAddOne(value1); // Just(85)

RemoteData

import { RemoteData, RD } from "@mvst/ts-unions";

// Create reusable functions by partially applying map
const format = RD.map((value: string) => value.toUpperCase());
const addTimestamp = RD.map((value: string) => `${value} (${new Date().toISOString()})`);

// Use them with different RemoteData values
const data = RD.success("Hello");

const formatted = format(data); // Success("HELLO")

// Compose functions using pipe
const formatAndAddTimestamp = pipe(format, addTimestamp);
const result = formatAndAddTimestamp(data1); // Success("HELLO (2024-03-21T12:00:00.000Z)")

Contributing

Please read CONTRIBUTORS.md for details on our code of conduct and the process for submitting pull requests.

License

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