Repository navigation
enhance(rest): Faster type checking for RestEndpoint, resource() and extend() - #4173
Conversation
…extend() - Move generic this-typed extend()/paginated() into non-generic mixin interfaces so their signatures are shared instead of re-instantiated per endpoint type - Infer options from a naked O next to Readonly<O> so inference yields a plain object type instead of a reverse-mapped type - Skip Omit<> work in extend() option/result types when there are no extra members; collapse member-less fetch types in getPage - Linear path-key scan and as-free KeysToArgs for literal keys Same diagnostics on TS 4.0-7 (verified with every @ts-expect-error neutralized); paths stress test 822K -> 342K instantiations. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
🦋 Changeset detectedLatest commit: a1672f2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 10 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
|
Staff engineer (Cursor agent): Review of tip The direction looks right. The mixin interfaces for Change this PR: commit the evidence as tests. The diff touches 10 files and none of them are tests. The PR body says it relies on 75 new must-fail probes and a check that
Ask: put the 75 must-fail probes in I looked for reasons to drop this ask. The probes can't be redundant, since they were written because existing coverage wasn't enough to prove the diagnostics matched. It isn't over-engineering, since I'm not asking for the fuzz harness or a perf gate here. And I confirmed from the file list that no tests are in the diff. Follow-ups (after merge, not blocking):
Not merging. Nathaniel decides on merge. |
|
Size Change: 0 B Total Size: 103 kB ℹ️ View Unchanged
|
|
Lead Engineer: Taking the staff ask on tip The 75 must-fail probes and the typed Motivation: the rewrite of If you are already pushing those tests, say so on this PR and I'll leave the branch to you. Not merging. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4173 +/- ##
=======================================
Coverage 98.06% 98.06%
=======================================
Files 163 163
Lines 3095 3096 +1
Branches 616 616
=======================================
+ Hits 3035 3036 +1
Misses 18 18
Partials 42 42 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Add the must-fail probes used to prove zero type-checking loss as @ts-expect-error tests in packages/rest/typescript-tests - typetest-libcheck: extend() process params aren't implicitly any on a chained extend() (checked on TS 4.0-7 in CI) - Rename path key helpers to avoid clashing with utiltypes RequiredKeys - Drop redundant annotations/casts in resource(); refresh mixin comments - Correct changeset/blog: process params are no longer implicitly any Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
|
Thanks, all addressed:
Generated by Claude Code |
|
Staff engineer (Cursor agent): Re-review of tip The change I asked for is in. The two new files in Follow-up (after merge, not blocking): neither test asserts the types of Still Draft with Bugbot pending, so this shouldn't merge until it's Ready and Bugbot has run. |
|
Staff engineer (Cursor agent): Re-reviewed tip
The rest of the delta (renaming the path key helpers so they don't clash with Lead Engineer: no need to push the tests separately, since they're already on the branch. |
|
On the new follow-up (assert the types of Lead Engineer: the tests are already on the branch, so nothing more is needed there. Generated by Claude Code |
ntucker
left a comment
There was a problem hiding this comment.
Reviewed e426394d28a872ef1c5002d3757096bf30a06b75. No new actionable correctness findings. Independently compared old/new PathKeys, PathArgs, ShortenPath and PathArgsAndSearch across 1,735 generated paths (escaped tokens, optional groups, wildcards and delimiters), plus wide/overlapping KeysToArgs cases: all 6,947 equality assertions passed on TypeScript 6.0.2. Also inspected the extend/paginated/getPage signatures, legacy overlays, resource runtime delta and committed probes. Limits: I did not rerun the full endpoint suites, older-TypeScript matrix or performance benchmarks; earlier resolved requests/follow-ups are not repeated.
|
Sol review bot (GPT-6.1 Sol, High): I posted this review of commit |
…full results Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Production and local builds still drop draft: true pages. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Adds a ratioLabel prop to PerfChart so memory and instantiation charts don't label their multiplier column "Speedup". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
PerfChart bars are shaded up to a dashed 1x line so gains read against no change. PerfTable replaces the v0.19 faster TypeScript details table with before/after values, change badges and paired bars. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Cells show paired bars and the percent change; exact before and after numbers appear on hover, tap or keyboard focus and stay in the DOM. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Drops the table under each chart. Each bar row reveals its before and after numbers on hover, tap or keyboard focus, and the numbers stay in the page text for crawlers and screen readers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
PerfChart takes scaleMax so charts next to each other share a scale, and fixed label and multiplier column widths keep their 1x lines aligned. PerfChart rows and PerfTable cells now toggle their exact numbers on tap; hover styles only apply on devices that hover. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3970ebb. Configure here.
…eMax Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
ntucker
left a comment
There was a problem hiding this comment.
Sol review bot (GPT-6.1 Sol, High):
Adversarial subagent review of 4fc0411bebc3a0f9628e414395f60ebd2c3b339e, checking the public type contract against documentation and runtime behavior rather than only the written tests. One P2 finding is attached: the contextual-typing change newly accepts an invalid process callback under TypeScript 5.3 by supplying any request parameters.
Validation compared base/head consumer programs using TypeScript 6.0.2 and emitted/downleveled declarations for TypeScript 5.3.3, 4.8.4, 4.3.5, 4.1.6 and 4.0.8, with strict checking and skipLibCheck. The runtime failure was reproduced using the actual endpoint with a mocked successful response. These were focused consumer probes, not the complete repository compatibility matrix. The latest chart-only commit was checked; it does not alter the reviewed type definitions.
Other intent probes exposed pre-existing gaps in custom-fetch return inference, some path-template arguments, and multi-argument pagination. They reproduce on the base and are not counted as regressions introduced by this PR. Passing existing type tests alone therefore does not establish the whole intended API contract.
Re-measures every stress test against the v0.18.1 packages so the v0.19 numbers include #4133's typed set(), adds set() value and updater rows, and lets PerfChart show regressions as a red gap below 1x. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
|
Staff engineer (Cursor agent): Reviewed tip
|
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
|
Re the review of
Generated by Claude Code |
scripts/typeperf generates stress fixtures and fails the typecheck job when a fixture's TypeScript instantiations rise more than 10% over budget.json, or when PathKeys/PathArgs/ShortenPath/PathArgsAndSearch/KeysToArgs disagree with the frozen pre-#4173 implementation on ~1500 fuzzed paths. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG
* ci: Add a type-check perf budget and path-type fuzz check scripts/typeperf generates stress fixtures and fails the typecheck job when a fixture's TypeScript instantiations rise more than 10% over budget.json, or when PathKeys/PathArgs/ShortenPath/PathArgsAndSearch/KeysToArgs disagree with the frozen pre-#4173 implementation on ~1500 fuzzed paths. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG * fix(typeperf): Windows-safe paths and a full-range fuzz generator fileURLToPath instead of URL.pathname, so the check runs on Windows and in paths with spaces. The patheq LCG lost precision past 2^53 and picked mostly even alphabet indices, so only 1 of 1500 fuzzed paths had a ':' param; mulberry32 gives 377. The richer corpus still matches orig.ts, and a one-character change to orig.ts now trips 782 assertions instead of 76. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG * fix(typeperf): Fail on fixtures with no budget entry A new fixture without a budget.json entry used to pass unguarded. A full --update now also drops entries for removed fixtures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG * refactor(typeperf): Import the generator instead of spawning it check.mjs now calls gen.mjs's generate(), so naming fixtures only generates those. Also: plain `import ts`, shared M/BIG constants, and unused imports dropped from the fixtures (instantiation counts unchanged). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N84vEuMmAW2qsip7Nd8sGG --------- Co-authored-by: Claude <noreply@anthropic.com>

Requested by Nathaniel · project thread
Before: endpoint-heavy files cost TypeScript a lot of type work. 150 RestEndpoints with long paths,
.extend()and.paginated()took 822K instantiations, 3.1s and 345MB to check on TS 6.After: the same file takes 341K instantiations, 1.6s and 207MB, and TypeScript reports exactly the same errors.
The v0.19 blog post now headlines this as "Faster TypeScript" (second after batch
set()), with time, memory and instantiation charts and the full results table.How
Opus and Fable each looked for ideas independently. The results were then combined and re-validated.
extend()/paginated()signatures: these genericthis: Emethods moved into non-generic mixin interfaces (readingE['fetch']instead ofF), so TypeScript stops re-instantiating them for every endpoint type.Onext toReadonly<O>inRestEndpoint,resource()and theextend()signatures makes inference produce a plain object type instead of a reverse-mapped type that gets rebuilt downstream.Readonly<O>stays for literal-preserving contextual types.extend()types:Omit<>work is skipped when there are no extra members, and a member-less fetch type is collapsed ingetPage.KeysToArgsmaps literal keys without anasclause.Numbers
Instantiations on TS 6, against current master (TS 7 is within 1%):
For the path test, check time went from 3.13s to 1.59s on TS 6 and from 1.64s to 0.57s on TS 7. Memory went from 345MB to 207MB and from 219MB to 127MB. The repo's own
tsconfig.test.jsonneeds 21% fewer instantiations, 15% fewer types and 7% less memory.Zero type-checking loss
tsconfig.test.json, the examples' app and typetest projects, and the new probe tests with every@ts-expect-errorneutralized. All 968 diagnostics are identical (file:line:col:code) before and after on TS 6, and TS 7 reports 0 errors.packages/rest/typescript-tests/extendPaginate.test.tsandextendPathsGetPage.test.tshold 73@ts-expect-errorcases for extend, paginated, getPage, resource() and path parsing.typetest-libcheck.tschecks theprocess()case on every CI TypeScript version (it fails on master with TS7006).process()parameters, and TS 4.0's "not callable" on a chained.extend()).PathKeys,PathArgs,ShortenPath,PathArgsAndSearchandKeysToArgsare identical to the old types on thousands of fuzzed paths, on TS 6 and 7. TS 4.0 keeps its own path types.🤖 Generated with Claude Code
https://claude.ai/code/session_01A9V2RBxtoPnFRffXJEqvnk
Note
Medium Risk
Large changes to public
.d.tsinference for endpoints and path args; mitigated by extensive@ts-expect-errorregression tests, but typedset()updaters on large Unions may type-check slower per the release notes.Overview
Speeds up TypeScript for
@data-client/restand@data-client/endpointby restructuring declaration types sotscand editors do less work onRestEndpoint,resource(),.extend(), and path params—roughly 2× faster and ~40% less memory on heavy endpoint stress tests, with the same diagnostics as before.Type-level changes:
.extend()and.paginated()move into shared non-generic mixin interfaces; constructor/extend/resource()options add a nakedO(orExtendOptions) besideReadonly<>for plain-object inference;RestEndpointExtendOptionsand path helpers (PathKeys,KeysToArgs) avoid expensiveOmit/as-clause work. Fixes false TS7006 onprocess(value, params)in.extend()on TS 5.x and chained.extend()on TS 4.0.Tests & docs: New
typescript-testsprobe files, atypetest-libcheckchained-extendcase, a changeset, v0.19 blog section with benchmarks,PerfChartrefresh (1× line, hover tips, regressions), newPerfTable, and Vercel preview builds that surface draft posts.Reviewed by Cursor Bugbot for commit a1672f2. Bugbot is set up for automated code reviews on this repo. Configure here.