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

typefoundry

v1.0.0

Published

TypeFoundry is a type-level utility for building **correlated TypeScript types**.

Readme

TypeFoundry

TypeFoundry is a type-level utility for building correlated TypeScript types.

It helps you describe an API as a set of independent variants and relationships, then generates the resulting union automatically.

Instead of manually maintaining large discriminated unions:

type SelectProp = TypeFoundry<{
  variants: {
    selectionMode: {
      single: {
        value: string;
      };

      multiple: {
        value: string[];
      };
    };

    control: {
      controlled: {
        onChange: (value: TypeFoundryRef<SelectProp, "value">) => void;
      };

      uncontrolled: {
        defaultValue: TypeFoundryRef<SelectProp, "value">;
      };
    };

};
}>;
type SelectProp =
  | {
      selectionMode: "single";
      value: string;
      control: "controlled";
      onChange: (value: string) => void;
    }
  | {
      selectionMode: "single";
      value: string;
      control: "uncontrolled";
      defaultValue: string;
    }
  | {
      selectionMode: "multiple";
      value: string[];
      control: "controlled";
      onChange: (value: string[]) => void; // <- same as value
    }
  | {
      selectionMode: "multiple";
      value: string[];
      control: "uncontrolled";
      defaultValue: string[]; // <- same as value
    };

Installation

npm install typefoundry

Basic usage

A simple variant model:

type ButtonProps = TypeFoundry<{
  variants: {
    size: {
      small: {
        padding: 4;
      };

      large: {
        padding: 12;
      };
    };
  };
}>;

Produces the equivalent of:

type ButtonProps =
  | {
      size: "small";
      padding: 4;
    }
  | {
      size: "large";
      padding: 12;
    };

But three two-state variants produce eight possible states. TypeFoundry constructs the combinations while keeping their relationships intact.

See more examples in the docs.


Who should use TypeFoundry?

Component library authors

If you're building reusable React components with combinations such as:

  • controlled / uncontrolled
  • single / multiple
  • synchronous / asynchronous
  • enabled / disabled
  • editable / read-only
  • virtualized / non-virtualized

TypeFoundry can keep those relationships represented in the type system.

Instead of maintaining dozens of union members manually, you define the dimensions and their relationships.


Design system teams

Design systems often have APIs where one option changes the meaning or type of another option.

For example:

variant
size
selection mode
interaction mode
loading mode
data source

As these dimensions grow, manually maintaining every valid combination becomes increasingly difficult.

TypeFoundry provides a single model from which those combinations are derived.


Headless component authors

Headless libraries often expose highly configurable APIs where behavior changes depending on several independent options.

TypeFoundry is useful when those relationships need to be visible to consumers through TypeScript rather than documented only in prose.


TypeScript library authors

You don't have to be building React components.

The same pattern can model any TypeScript API where:

the type of one property depends on the state of another property.

Examples include:

  • configuration objects
  • client APIs
  • state machines
  • builder configuration
  • plugin options
  • protocol models
  • strongly typed library options

Why use TypeFoundry?

Chances are you don't, see why.

Without TypeFoundry

Complex APIs often become manually maintained unions:

type Props = CaseA | CaseB | CaseC | CaseD | CaseE | CaseF;
// ...

Adding another independent dimension can multiply the number of cases you need to reason about.

With TypeFoundry

You describe the dimensions:

variants: {
  selectionMode: { ... };
  control: { ... };
  searchable: { ... };
  creation: { ... };
}

and correlations where types need to stay synchronized:

Ref<"selectionMode", "value">;

The resulting type is generated from the model.


TypeFoundry is not a runtime schema library

TypeFoundry focuses on TypeScript API modeling.

It does not try to replace runtime validation libraries.

You can continue using tools such as runtime validators alongside TypeFoundry when runtime validation is required.

Its job is to make the static API contract precise.


When TypeFoundry may not be necessary

You probably don't need TypeFoundry for simple APIs.

If your component only has a couple of independent props:

type ButtonProps = {
  label: string;
  disabled?: boolean;
};

normal TypeScript is already excellent.

TypeFoundry becomes useful when your API starts accumulating multiple correlated states and constraints.