The problem
Every TypeScript library maintainer knows this moment.
You open a PR, and someone comments: "Wait, is this a major or minor bump?"
You look at the diff. You changed a return type somewhere. Or added a required parameter. Or renamed an interface property. Suddenly it's a 10-minute discussion about whether your change is breaking or not — and half the time, people just go with their gut.
Tools like conventional-commits help, but they depend on the developer correctly labeling their own commits. If I add a required parameter and write feat: instead of feat!:, nothing will catch that.
What if we just... looked at the types?
TypeScript already knows everything about your API surface. It knows what you exported, what the signatures look like, what changed between versions.
So I built semver-checks — a CLI that diffs your TypeScript API between two git refs and tells you exactly what semver bump is required.
npx semver-checks compare v1.0.0 HEAD
Output:
BREAKING CHANGES (2):
required-property-added: Required property 'timeout' was added
return-type-changed: Return type of 'findUser' changed
FEATURES (1):
export-added: Export 'createConfig' was added
Recommendation: MAJOR
No opinions. No commit message parsing. Just TypeScript types, diffed mechanically.
How it works
semver-checks extracts your exported API at two points in time — using git refs or local paths — and compares them using 40+ classification rules.
MAJOR (breaking): export removed, required param added, return type changed, property type changed, enum member removed...
MINOR (new feature): export added, optional param added, interface method added, overload added...
PATCH: anything that doesn't affect existing consumers.
You can also use it programmatically:
import { compare } from 'semver-checks';
const report = await compare({
oldSource: { type: 'git', ref: 'v1.0.0' },
newSource: { type: 'path', path: '.' },
});
console.log(report.recommended); // 'major' | 'minor' | 'patch'
console.log(report.changes); // ApiChange[]
CI integration
The --strict flag exits with code 1 if breaking changes are detected — perfect for CI:
- name: Check for breaking changes
run: npx semver-checks compare v1.0.0 HEAD --strict
Now your pipeline fails if someone accidentally ships a breaking change without bumping the major version.
Honest limitations
It's not magic — here's what it can't do:
- Behavioral changes (only API surface is analyzed)
- Default exports (named exports only, for now)
- Requires
tsconfig.jsonin the analyzed project - Semantically equivalent types may produce false positives (
string | numbervsnumber | string)
Try it
npx semver-checks compare v1.0.0 HEAD
GitHub: https://github.com/kyungseopk1m/semver-checks
If you hit edge cases or missing rules, open an issue — contributions welcome.
Tags: typescript opensource npm node

Top comments (0)