Skip to content

feat(types): opt-in flat NitroFetchRequest to bound $fetch type instantiation - #4477

Open
Killian-Aidalinfo wants to merge 1 commit into
nitrojs:mainfrom
aidalinfo:fix/typed-fetch-instantiation-v3
Open

feat(types): opt-in flat NitroFetchRequest to bound $fetch type instantiation#4477
Killian-Aidalinfo wants to merge 1 commit into
nitrojs:mainfrom
aidalinfo:fix/typed-fetch-instantiation-v3

Conversation

@Killian-Aidalinfo

Copy link
Copy Markdown

🔗 Linked issue

Closes #4476

❓ Type of change

  • 🚀 Enhancement (opt-in, non-breaking)

📚 Description

Apps with a large generated InternalApi (hundreds of routes) hit TS2589 (Type instantiation is excessively deep) and, under tsgo, a flood of TS2321 on typed $fetch / useFetch / useAsyncData / event.$fetch calls. NitroFetchRequest is the union of all route keys used as the generic constraint (R extends NitroFetchRequest), so every call site re-scores the URL literal against the full union via MatchedRoutes/AvailableRouterMethod/TypedInternalResponse. tsc sits just under its 5M instantiation limit; tsgo (stricter, stable type ordering) tips over → the whole diagnostic class.

This is the same family the TypeScript team closes as intended / NOT_PLANNED, pointing to libraries to fix their types (microsoft/typescript-go#929, #4465, #787) — so the mitigation belongs here.

This PR adds an opt-in, non-breaking escape hatch — a NitroFetchConfig interface:

declare module "nitropack" {
  interface NitroFetchConfig { flatRequest: true }
}

When opted in, NitroFetchRequest resolves to string, which stops the per-call-site union scoring. Default is unchanged (the union) so existing users keep full request autocomplete + typing. When enabled, response typing is preserved (MatchedRoutes<R> still resolves the return type from the URL literal); only request-key autocomplete is traded away.

✅ Why this approach

  • Non-breaking: gated behind an interface users must explicitly augment; default resolves to the current union.
  • Keeps response typing: TypedInternalResponse/MatchedRoutes are untouched.
  • Minimal: one type-only change in src/types/fetch/fetch.ts.

Alternatives rejected: making MatchedRoutes non-recursive or emptying InternalApi destroys response typing (trades TS2589 for a flood of TS2339/TS18046); changing only the $Fetch default R has no effect (the union must stay in the constraint for autocomplete, and that union is exactly what over-instantiates).

🧪 Measured

On a real Nuxt 4 app (~846 routes): removes the entire TS2589/TS2321 class on both tsc and tsgo with zero new errors, response types preserved.

Note: the same change applies cleanly to the v2 branch (nitropack 2.13.x) if a backport is wanted.

…ntiation

Projects with a large generated InternalApi (hundreds of routes) can hit
"Type instantiation is excessively deep and possibly infinite" (TS2589) and
"Excessive stack depth comparing types" (TS2321) on typed $fetch / useFetch /
useAsyncData / event.$fetch, because the NitroFetchRequest route-key union is
used as the generic constraint and re-scored at every call site.

Add an opt-in NitroFetchConfig interface: when a project sets
`{ flatRequest: true }`, NitroFetchRequest resolves to `string`, which stops the
per-call-site scoring of the route union. Response typing is preserved
(MatchedRoutes still resolves the return from the URL literal); only request-key
autocomplete is traded away. Default behavior is unchanged (union), so existing
users are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Killian-Aidalinfo
Killian-Aidalinfo requested a review from pi0 as a code owner July 23, 2026 19:31
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

@Killian-Aidalinfo is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9826dc2a-f461-490a-bc43-91520d898bc7

📥 Commits

Reviewing files that changed from the base of the PR and between 77b77ff and eada2be.

📒 Files selected for processing (1)
  • src/types/fetch/fetch.ts

📝 Walkthrough

Walkthrough

NitroFetchRequest now supports an opt-in flatRequest configuration that resolves requests to string, while preserving route-aware typing by default.

Changes

Fetch request typing

Layer / File(s) Summary
Fetch typing contract
src/types/fetch/fetch.ts
Adds the exported NitroFetchConfig interface and preserves the route-aware request construction through RouterMethod and TypedNitroFetchRequest.
Flat request mode
src/types/fetch/fetch.ts
Makes NitroFetchRequest resolve to string when NitroFetchConfig is augmented with flatRequest: true; otherwise it uses the typed request union.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title uses a conventional commit prefix and clearly summarizes the opt-in fetch type change.
Description check ✅ Passed The description is directly related to the type-only escape hatch and explains the motivation and effect of the change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Killian-Aidalinfo

Copy link
Copy Markdown
Author

Hi @pi0 , I opened this PR to fix the type-instantiation issues we're seeing with the Go version of vue-tsc (tsgo).

There have already been several issues opened on the Microsoft side, but they were closed as intended / not planned, with the recommendation that libraries patch their own types instead.

The approach here is intentionally minimal and opt-in. It adds an escape hatch for users hitting these limits while keeping the current behavior by default. Response typing is still preserved, the only trade-off is request-path autocomplete when the option is enabled.

I tested it on a fairly large Nuxt 4 project (~846 routes), and it gets rid of the TS2589/TS2321 errors on both tsc and tsgo without introducing any new ones.

Let me know what you think 🙂

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.

Typed $fetch route union causes TS2589/TS2321 (excessive type instantiation) on apps with many routes

1 participant