Skip to content

Type-check main.d.ts in CI - #45

Merged
jstayton merged 2 commits into
developmentfrom
typecheck-declarations
Aug 27, 2026
Merged

Type-check main.d.ts in CI#45
jstayton merged 2 commits into
developmentfrom
typecheck-declarations

Conversation

@jstayton

@jstayton jstayton commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

main.d.ts is the published types entry, but nothing verified it — npm test only runs node --test over the JS, so the declarations could drift from main.js without anything failing. AGENTS.md asks for the two to be kept in sync, which until now was a manual promise.

src/main.test-d.ts exercises the declared API at compile time and never runs; tsc failing to compile it is the failure. Each option's omission and each option's type get their own @ts-expect-error, one directive per property, so a single option drifting can't hide behind another. Those directives are load-bearing in both directions — if a declaration ever gets looser, the line stops erroring and tsc fails on the unused directive. That's what catches a widening to unknown or any.

To check the gate actually bites rather than just passing green, I mutated main.d.ts 18 ways: each of the four required options made optional, widened to unknown, and widened to any; leewayMinutes retyped and made required; the return type widened to boolean; an index signature admitting arbitrary keys; the error name widened off its literal; and the error class dropped from the namespace. All 18 fail the check.

An earlier revision of this PR claimed a six-mutation check passed clean. That was true but misleading — those six happened to be mutations the file already covered. Review correctly caught that url, secret, and header could turn optional, and that all four required options could widen, with zero diagnostics. Now fixed, and the mutation matrix covers the declared surface rather than a sample of it.

typescript is the only new dependency and it's dev-only, so the package stays zero-dependency at runtime. The type test is excluded from the tarball — npm pack --dry-run still lists just package.json, error.js, main.d.ts, and main.js.

On the filename: .test-d.ts rather than main.d.test.ts or main.test.d.ts, because TypeScript treats any .d.<something>.ts as a declaration file, which makes the helper body and the @ts-expect-error assertions illegal in an ambient context.

🤖 Generated with Claude Code

jstayton and others added 2 commits August 27, 2026 09:53
`main.d.ts` is the published `types` entry, but nothing verified it.
`npm test` only runs `node --test` over the JS, so the declarations
could drift from `main.js` without anything failing.

`src/main.test-d.ts` exercises the declared API at compile time and
never runs — `tsc` failing to compile it is the failure. The
`@ts-expect-error` directives are load-bearing in both directions, since
a declaration that gets looser stops erroring and then fails on the
unused directive.

Verified by mutating `main.d.ts` six ways: widening the return type to
`boolean`, making `body` optional, retyping `leewayMinutes`, adding an
index signature, widening the error `name`, and dropping the error class
from the namespace. All six fail the check.

The type test is excluded from the published package.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only `body`'s requiredness and `leewayMinutes`'s type were negatively
tested, so `url`, `secret`, and `header` could turn optional — and all
four required options could widen to `unknown` or `any` — with zero
diagnostics.

Each option now gets its own omission case and its own wrong-type case,
one directive per property, so a single option drifting can't hide
behind another. The wrong-type cases are what catch a widening: the call
stops erroring and `tsc` fails on the unused directive.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jstayton
jstayton merged commit 4509d34 into development Aug 27, 2026
4 checks passed
@jstayton
jstayton deleted the typecheck-declarations branch August 27, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant