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

rtt

v1.3.4

Published

Runtime Typescript Types

Readme

rtt — Runtime Types for TypeScript

npm version License: MIT

TypeScript types vanish at runtime. rtt brings them back — with zero dependencies and a tiny footprint.


The Problem

When TypeScript compiles to JavaScript, all type information is stripped away. This creates a frustrating gap:

// ✅ At compile time — TypeScript knows this is a Dog
const dog: Dog = { name: 'Rover', breed: 'Labrador' };

// ❌ At runtime — it's just a plain object. No type info remains.
JSON.parse('{"name":"Rover","breed":"Labrador"}') // what IS this?

Without runtime type information, you're forced into fragile workarounds: manual type strings, instanceof checks that don't survive serialization, or heavy validation libraries like Zod for every use case.

The Solution

rtt lets you define first-class type descriptors that carry both runtime identity and compile-time TypeScript types — enabling inheritance-aware runtime type checking with a single function call:

import {$type, is} from 'rtt';

// 1️⃣ Define your type hierarchy
const $Animal = $type<Animal>('app.Animal');
const $Dog    = $type<Dog>('app.Dog', $Animal);
const $Cat    = $type<Cat>('app.Cat', $Animal);

export type Animal = {$type: $Type; name: string};
export type Dog  = Animal & { breed: string };
export type Cat  = Animal & { lives: number };

// 2️⃣ Create typed objects with descriptor metadata
const rover: Dog    = {$type: $Dog, name: 'Rover', breed: 'Labrador'};
const whiskers: Cat = {$type: $Cat, name: 'Whiskers', lives: 9};

// 3️⃣ Check types at runtime
is(rover, $Dog);       // ✅ true
is(rover, $Animal);    // ✅ true — inheritance works!
is(whiskers, $Dog);    // ❌ false

Features

| Feature | Description | |---|---| | 🏗️ Type Hierarchies | Define parent-child relationships and check them at runtime | | 🔍 Runtime Introspection | Know exactly what type an object is, even after JSON round-trips | | ⚡ Zero Dependencies | No bloat — just two functions and a lightweight interface | | 📦 Tiny Footprint | Minimal bundle size, tree-shakeable ESM exports | | 🔒 Type Narrowing | is() returns a TypeScript type guard for safe downstream access | | 🧬 Generic Type Support | Compare parameterized types with their arguments | | 🏷️ Branded Types | Optional structural branding for compile-time + runtime safety |

Quick Start

Installation

npm install rtt
# or yarn add rtt / pnpm add rtt

Type Narrowing

The is() function is a type guard — TypeScript narrows the type automatically:

const unknownUser: unknown = {$type: $User, name: 'John'};

if (is(unknownUser, $User)) {
  // ✅ TypeScript knows user has 'name'
  console.log(`Hello, ${unknownUser.name}`);
}

Generic Types

Type descriptors work with generic types too — pass the inner type as a generics argument:

import {$type, is} from 'rtt';

// Define base types
const $User = $type<User>('app.User');
const $List = <T>($generic: $Type<T>) => $type<List<T>>('app.List', undefined, [$generic]);

export type User = {$type: $Type; name: string};
export type List<T> = {$type: $Type; items: T[]};

// Tag objects
const user: User    = {$type: $User, name: 'John'};
const userList: List<User> = {$type: $List($User), items: [user]};

// Runtime checks preserve generic types
const unknownUser: unknown = user;
const unknownList: unknown = userList;

if (is(unknownUser, $User)) {
  console.log(unknownUser.name); // ✅ ok
}

if (is(unknownList, $UserList)) {
  console.log(unknownList.items[0].name); // ✅ ok — generic preserved!
}

API Reference

$type<T>(name, parent?, generics?)$Type<T>

Creates a named type descriptor that can be composed into hierarchies. The generic parameter T connects the runtime descriptor to your TypeScript type.

const $Animal = $type<Animal>('app.Animal');
const $Dog    = $type<Dog>('app.Dog', $Animal);

| Param | Type | Description | |---|---|---| | name | string | Unique type identifier (e.g. 'app.Dog') | | parent? | $Type \| null | Parent type for inheritance chains | | generics? | $Type[] | Generic type arguments to compare |

To tag a runtime object with a descriptor, spread it explicitly:

const rover: Dog = {$type: $Dog, name: 'Rover', breed: 'Labrador'};

$nominal<I, P>(id, parent?, generics?)<T>()$Nominal<I, T & P>

Creates a branded nominal type factory that produces values carrying $type metadata automatically.

const $UserId = $nominal('app.UserId')<{id: number}>();
const user = $UserId({id: 42});

| Param | Type | Description | |---|---|---| | id | string | Unique nominal identifier | | parent? | $Nominal<string, P> \| null | Parent nominal type for inheritance chains | | generics? | $Type[] | Generic type arguments to compare |

is<T>(value, type)value is T

Runtime type guard. Returns true if value.$type matches type or any of its ancestors in the hierarchy.

if (is(rover, $Dog)) {
  // TypeScript narrows: rover is now typed as Dog
  console.log(rover.name); // ✅ safe
}

isType(a, b)boolean

Low-level comparison between two $Type descriptors. Handles inheritance chains and generic type matching internally.

$Type<T> Interface

interface $Type<T = unknown> {
  name: string;
  type?: T;
  parent?: $Type | null;
  generics?: $Type[] | null;
}

Brand<T> Type

A structural branding utility for compile-time + runtime safety:

import {Brand} from 'rtt';

type UserId = Brand<'UserId'> & number;

Development

npm install
npm test        # Run vitest suite
npm run build   # Build with Vite + dts (generates dist/)

License

MIT — © Nizami