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-safe-union

v1.1.1

Published

A TypeScript utility for safely destructuring union types while maintaining type safety

Readme

ts-safe-union

npm version Build Status License: MIT

A TypeScript utility for destructuring discriminated unions while maintaining type safety. This package is tiny (no dependencies) and solves a common problem in Typescript. Broadly, this package helps with:

  • Safely destructuring discriminated unions
  • Making switch/case statements exhaustive
  • Improving state management patterns
  • Handling API responses more safely
  • Reducing boilerplate type guards

Installation

npm install ts-safe-union

Motivation

In TypeScript, when working with discriminated unions, you normally can't destructure properties that don't exist on all members of the union:

// Before: Normal TypeScript union
type StateA = { state: "A"; A: number };
type StateB = { state: "B"; B: string };
type State = StateA | StateB;

// Error: Property 'B' does not exist on type 'StateA'
const { state, A, B } = someState;

Helpfully, ts-safe-union was designed to improve this behavior:

// After: Using DiscriminatedUnion
type State = DiscriminatedUnion<
  "state",
  {
    A: { A: number };
    B: { B: string };
  }
>;

// Works! Properties are safely destructurable
const { state, A, B } = someState;

Usage

DiscriminatedUnion

Use DiscriminatedUnion when you have a well-defined discriminating property (e.g. status, type, etc.) or you have many states.

import { DiscriminatedUnion } from "ts-safe-union";

// Define your discriminated union type
type RequestState = DiscriminatedUnion<
  "status", // The discriminator property name
  {
    // Each key defines a variant with its properties
    loading: { progress: number };
    success: { data: unknown };
    error: { error: Error };
  }
>;

// Example request consumer
const handleRequest = (request: RequestStateWithCommon) => {
  const { status, progress, data, error } = request;

  if (status === "loading") {
    console.log(`Loading: ${progress}%`);
  } else if (status === "success") {
    console.log(`Success: ${JSON.stringify(data)}`);
  } else {
    console.log(`Error: ${error.message}`);
  }
};

If you want to define your keys elsewhere, you can provide them to the Discriminated Union and the TS complier will give you errors if some variant are not supplied in the list. For example, the following example will have a type error because the error variant is not specified.

import { DiscriminatedUnion } from "ts-safe-union";

const statusKeys = ["loading", "success", "error"] as const;

type RequestState = DiscriminatedUnion<
  "status",
  {
    loading: { progress: number };
    success: { data: unknown };
  },
  typeof statusKeys[number] // << error here
>;

MergedUnion

Use MergedUnion when you want to merge two existing object types into a single union while maintaining safe property access.

import { MergedUnion } from "ts-safe-union";

// Define your individual state types
type Success = { state: "success"; data: unknown };
type Error = { state: "error"; error: Error };

// Merge them into a union type
type RequestState = MergedUnion<Success, Error>;

const handleRequest = (request: RequestState) => {
  const { state, data, error } = request;

  if (state === "success") {
    console.log(`Success: ${JSON.stringify(data)}`);
  } else {
    console.log(`Error: ${error.message}`);
  }
};

More Examples

Check out the examples directory for simple but practical use cases:

Contributing

Contributions are welcome! Please feel free to submit a PR. If you feel comfortable, also:

  1. Add tests for any new features
  2. Update documentation if needed
  3. Ensure all tests pass by running npm test

License

MIT © Jomity