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

@typefirst/typist

v1.0.3

Published

A minimal, compositional, and debug-friendly suite of type-level utilities for TypeScript

Downloads

187

Readme

Typist: Primitive Type-First Utilities

Show what your types are made of

Typist is a collection of small, focused utilities for type-level debugging and static validation in TypeScript.

  • 🔍 Type Assertions – Compiler-enforced static assertions for compilable proofs
  • 🧱 Type Materialization - Utilities for resolving complex inferred types
  • 🎭 Phantom Types – Runtime-agnostic operators for flexible type transportation and inference logic
  • ⚖️ Verdict Encoding – Rich error reporting techniques for recursive and conditional type inspection techniques with customizable diagnostic type-level metadata
  • 🧩 Symbolic Inference – Type manipulation as first-class operations
  • 🫙 Scope Blocks - Block-based grouping for type-level test suites
  • 🚀 Zero Runtime – Pure compile-time operations
  • 📦 ESM Ready – Modern module system support

Essential Primitives for Type-First Development

Typist exists to support a type‑first approach to software development: leveraging the compiler as an active analytical tool, enforcing architectural constraints, validating domain models, and enabling precise, inference‑driven workflows. This can significantly strengthen code generation capability.

Zero Cost

Typist has no dependencies, virtually zero runtime overhead, and bundles less than 1KB gzipped and uglified.

API Reference

Assertions

Assertions are compile-time guarantees. Each is a function that returns void and causes a TypeScript error if its condition is false.

is_<Type>(thing)

Asserts that thing is assignable to Type.

Alias: assignable_

const timestamp = Date.now()

is_<number>(timestamp)

// @ts-expect-error
is_<string>(timestamp)

has_<Key, Value?>(thing)

Asserts that thing has a property Key, optionally with value type Value.

const person = { name:'ponyboy', age:15 }

has_<'age'>(person)
has_<'name', string>(person)

// @ts-expect-error
has_<"email">(person)

extends_<A, B>()

Asserts that A extends B.

type User = { email:string, admin:boolean }
type AdminUser = User & { admin:true }

extends_<AdminUser, User>()

const user
  = { email:'[email protected]', 
      admin:false } as const

extends_<typeof user, User>()

// @ts-expect-error
extends_<typeof user, AdminUser>()

instance_<Ctor>(value)

Asserts that value is an instance of constructor type Ctor.

class Dog {}
class Cat {}

const dog = new Dog()

instance_<Dog>(dog)

// @ts-expect-error
instance_<Cat>(dog)

never_<T>()

Asserts that a type resolves to never.

type Impossible = Extract<'a', 'b'>

never_<Impossible>()

// @ts-expect-error
never_<string>()

Verdict Assertions

These consume $Verdict result types ($Yes or $No).

Generic verdict types allow us to write maximally complex evaluative logic beyond what is possible using only standalone assertion functions, such as conditional recursion. We can test for conditions like strict equality (bidirectional assignability).

  • yes_ — requires $Yes
  • no_ — requires $No
  • assert_ — requires $Yes or true
yes_<$Equal<'✌️', '✌️'>>

no_<$Equal<'✌️', string>>

yes_<$Extends<'✌️', string>>

// @ts-expect-error
yes_<$Extends<string, ✌️>>

Verdicts

Verdicts represent explicit yes/no results with diagnostic metadata. You can perform maximally complex type evaluations using recursive conditional logic by writing generic verdict types that resolve to $Yes or $No.

$Yes

Indicates success.

$No<Message, Dump>

Captures metadata at failure path. This is the type-level version of throwing a runtime error with { message, data }.

  • message: string
  • dump: readonly any[]

Verdict Utilities

Commonly useful verdict utility types that ship out-of-the-box: $Equal<A, B>, $Extends<A, B>

Phantom Values

A phantom value is a nominal runtime value used solely to transport type information.

phantom_<T>(value?)

Creates a value with type T. The argument value is optional, ignored by the compiler, but retained at runtime if you supply it.

Alias: p_, type_, t_, force_

type Person = { name:string; age:number }

const person_ = phantom_<Person>()

is_<Person>(person_)

// @ts-expect-error
is_<string>(person_)

Operators

Operators return phantom values. They manipulate or capture type identity.

assign_<T>(value)

Returns the provided value as type T, enforcing that the original value type is assignable to T. Used to safely widen types to be less specific while preserving runtime value.

Alias: as_, widen_

const narrow = 'hello'

is_<'hello'>(narrow)

const wide = assign_<string>(literal)

is_<string>(wide)

// @ts-expect-error
is_<'hello'>(wide)

nope_(value?)

Produces a phantom typed as never, preserving runtime value.

const neverFoo = nope_('foo')

any_(value?)

Produces a phantom typed as any, preserving runtime value.

Alias: __

const anyBar = any_('bar')

resolve_<T>(value?)

Returns an expanded representation of T, resolving its property names. This expansion is semantically equivalent to the original (mutually assignable), but easier to inspect.

Aliases: r_

_r<T> is the type version of resolve_, which we can use with type definitions.

type Expanded = _r<Original>

flush_<T>(value?)

Recursive version of resolve_. Expands nested structures while remaining equivalent to the original type.

Aliases: f_

_r<T> is the type version of resolve_, which we can use with type definitions.

type Deep = _f<ComplexType>;

Blocks

Blocks provide scope to prevent pollution. The type and runtime value returned by fn is passed through. This is the type version of a describe() block in a runtime assertion library.

example_(label?, fn)

Runs fn, allows assertions inside it, and returns the type of the final expression.

Aliases: test_, proof_.

const exampleUser
  = example_('user', () => 
    { const user = createUser('bob')
      is_<User>(user)
      has_<'id'>(user)
      return user } )