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

@evrys/tsdiff

v0.0.1

Published

Detect breaking changes in a TypeScript package's public API surface

Readme

tsdiff

Detect breaking changes in a TypeScript package's public API surface.

Inspired by oasdiff for OpenAPI specs — but for .d.ts files.

tsdiff loads the previous and the new declaration file into a single TypeScript program and uses the compiler's own type checker to determine whether the new API is assignment-compatible with the old one. That makes it stricter and more accurate than text diffing, and catches subtle issues like narrowed parameter types, widened required fields, or removed overloads.

Install

pnpm add -g tsdiff
# or use without installing
pnpm dlx tsdiff <old.d.ts> <new.d.ts>

(npm and yarn work too — tsdiff is a regular npm package.)

Usage

tsdiff path/to/old.d.ts path/to/new.d.ts

Exits with a non-zero status when at least one breaking change is detected, so it can be wired straight into CI.

Options

| Flag | Description | | --- | --- | | --format <human\|json> | Output format. Default: human. | | --no-exit-code | Always exit with status 0, even when breaking changes are found. |

Example

$ tsdiff before.d.ts after.d.ts
✖ 2 breaking change(s)
  • Export `parseFoo` (function) was removed
  • Export `Config` has an incompatible type (new value not assignable to old type)
      old: { id: string; name?: string; }
      new: { id: string; name: string; }
+ 1 non-breaking change(s)
  • Export `parseBar` (function) was added

Programmatic API

import { diffDeclarations, formatHuman } from "tsdiff";

const result = diffDeclarations("./old.d.ts", "./new.d.ts");
console.log(formatHuman(result));

if (result.breakingCount > 0) process.exit(1);

What it detects

  • Removed exports (breaking)
  • Added exports (non-breaking)
  • Kind changes (e.g. functionvariable)
  • Function signature changes — new required parameters, narrowed parameter types, widened return types
  • Interface / type-alias shape changes — new required fields, removed fields, narrowed unions
  • Class member changes
  • Cross-cutting type assignability via the TypeScript checker

What it does not (yet) detect

  • Comparing whole packages from npm specifiers (planned)
  • JSDoc @deprecated tracking
  • Suggesting a SemVer bump
  • Markdown / GitHub Actions output

PRs welcome.

How it works

  1. Both .d.ts files are loaded into a single ts.Program via a virtual root that does:
    import * as __old from "<old>";
    import * as __new from "<new>";
  2. The exports of each module-namespace symbol are walked to build an API surface map.
  3. For each name present in both surfaces, tsdiff compares the symbol kinds and uses checker.isTypeAssignableTo in both directions to classify the change.

License

MIT