nextjs - ✅(Solved) Fix typedRoutes invalid Link href is not enforced by tsc in a workspace app unless .next/types/link.d.ts is manually referenced [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#93007Fetched 2026-04-20 11:58:29
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
cross-referenced ×1labeled ×1referenced ×1

Error Message

src/app/page.tsx(6,10): error TS2322: Type '"/definitely-not-a-real-route"' is not assignable to type 'UrlObject | RouteImpl<"/definitely-not-a-real-route">'.

Root Cause

The repro is intentionally a tiny monorepo/workspace because I could not reproduce this in a standalone single-package Next app. The mismatch seems to depend on a shared tsconfig package + app package setup.

PR fix notes

PR #93047: fix(typegen): include link.d.ts in next-env.d.ts when typedRoutes is enabled

Description (problem / solution / changelog)

What

When typedRoutes: true is configured, next-env.d.ts must include an import of link.d.ts for TypeScript to enforce typed routes. Previously the import was nested inside the strictRouteTypes conditional block, so it was only emitted when experimental.strictRouteTypes was also enabled.

Why

In workspace/monorepo setups TypeScript resolves module augmentations differently — the import './.next/types/link.d.ts' in next-env.d.ts is required for the next/link route type to be augmented and invalid href values to be caught by tsc.

Fix

Move the link.d.ts import to a standalone typedRoutes check so it is always included when typedRoutes: true, regardless of strictRouteTypes. Updated unit tests to reflect the new expected output.

Fixes #93007

Changed files

  • packages/next/src/lib/typescript/writeAppTypeDeclarations.ts (modified, +7/-7)
  • test/unit/write-app-declarations.test.ts (modified, +6/-0)

Code Example

bun install

---

bun run -F @repro/web typegen

---

bun run -F @repro/web tsc
bun run -F @repro/web tsc:noemit

---

<Link href="/definitely-not-a-real-route">Broken typed route</Link>

---

bun run -F @repro/web tsc:with-link-augmentation

---

src/app/page.tsx(6,10): error TS2322: Type '"/definitely-not-a-real-route"' is not assignable to type 'UrlObject | RouteImpl<"/definitely-not-a-real-route">'.

---

next typegen && tsc --noEmit

---

Operating System:
  Platform: darwin
  Arch: arm64
Binaries:
  Node: 24.12.0
  Bun: 1.3.12
Relevant Packages:
  next: 16.2.4
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3

---

/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/jakeleventhal/next-typed-routes-workspace-tsc-repro

To Reproduce

  1. Clone the repo
  2. Install dependencies:
bun install
  1. Generate route types:
bun run -F @repro/web typegen
  1. Confirm the generated files:
  • apps/web/.next/types/routes.d.ts contains only /
  • apps/web/.next/types/link.d.ts contains the next/link and next/navigation route augmentations
  • apps/web/next-env.d.ts imports ./.next/types/routes.d.ts
  1. Run TypeScript from the app package:
bun run -F @repro/web tsc
bun run -F @repro/web tsc:noemit
  1. Notice that both commands succeed, even though apps/web/src/app/page.tsx contains an invalid route:
<Link href="/definitely-not-a-real-route">Broken typed route</Link>
  1. Now run the comparison script that explicitly loads the generated link.d.ts file:
bun run -F @repro/web tsc:with-link-augmentation
  1. Notice that this fails immediately with:
src/app/page.tsx(6,10): error TS2322: Type '"/definitely-not-a-real-route"' is not assignable to type 'UrlObject | RouteImpl<"/definitely-not-a-real-route">'.

Current vs. Expected behavior

Current:

  • typedRoutes: true is enabled
  • next typegen generates both routes.d.ts and link.d.ts
  • In this workspace-style setup, both tsc --build and tsc --noEmit still accept an invalid Link href
  • If I manually reference .next/types/link.d.ts, the same invalid route is rejected

Expected:

After next typegen, plain TypeScript checking should reject the invalid Link href without requiring a manual reference to .next/types/link.d.ts.

This expectation seems consistent with the docs for next typegen, which say:

next typegen && tsc --noEmit

should validate route usage externally.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
Binaries:
  Node: 24.12.0
  Bun: 1.3.12
Relevant Packages:
  next: 16.2.4
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3

Which area(s) are affected? (Select all that apply)

TypeScript

Which stage(s) are affected? (Select all that apply)

next typegen, tsc --build, tsc --noEmit

Additional context

The repro is intentionally a tiny monorepo/workspace because I could not reproduce this in a standalone single-package Next app. The mismatch seems to depend on a shared tsconfig package + app package setup.

The generated next-env.d.ts in the repro currently looks like this:

/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";

That appears to be enough for route metadata, but not enough for next/link route enforcement in this setup.

extent analysis

TL;DR

The issue can be resolved by ensuring that the link.d.ts file is properly referenced and utilized during the TypeScript checking process, potentially by adjusting the tsconfig settings or the import statements in the next-env.d.ts file.

Guidance

  • Review the tsconfig settings to ensure that the link.d.ts file is included in the compilation process, possibly by adding an explicit reference to it.
  • Verify that the next-env.d.ts file correctly imports and references the link.d.ts file, allowing the route augmentations to be applied.
  • Consider adjusting the import statement in next-env.d.ts to directly reference link.d.ts, ensuring that the route types are properly enforced.
  • Investigate the monorepo/workspace setup to understand how the shared tsconfig package and app package configuration might be impacting the type checking behavior.

Example

No specific code example is provided due to the complexity of the issue and the need for a more detailed understanding of the project's configuration.

Notes

The issue seems to be related to the specific monorepo/workspace setup and the interaction between the tsconfig settings, the generated next-env.d.ts file, and the link.d.ts file. Further investigation into the project's configuration and the TypeScript version being used may be necessary to fully resolve the issue.

Recommendation

Apply a workaround by manually referencing the link.d.ts file in the next-env.d.ts file or adjusting the tsconfig settings to include the link.d.ts file in the compilation process, as this appears to be the most direct way to ensure that the route types are properly enforced.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING