Skip to content

fix(types): relax RouteMapGeneric constraint for interface-based RouteNamedMap#2624

Merged
posva merged 1 commit intovuejs:mainfrom
YevheniiKotyrlo:fix/relax-routemapgeneric-constraint
Feb 12, 2026
Merged

fix(types): relax RouteMapGeneric constraint for interface-based RouteNamedMap#2624
posva merged 1 commit intovuejs:mainfrom
YevheniiKotyrlo:fix/relax-routemapgeneric-constraint

Conversation

@YevheniiKotyrlo
Copy link
Contributor

@YevheniiKotyrlo YevheniiKotyrlo commented Feb 12, 2026

Problem

When using file-based routing (vue-router/vite), the generated typed-router.d.ts augments RouteNamedMap as an interface with literal route keys. However, 14 typed route helper types in route-location.ts use the constraint RouteMap extends RouteMapGeneric where RouteMapGeneric = Record<string | symbol, RouteRecordInfoGeneric>.

TypeScript interfaces with only literal keys do not have implicit index signatures (see TypeScript#15300), so the augmented RouteNamedMap fails to satisfy Record<string | symbol, ...>. This produces 12 TS2344 errors with skipLibCheck: false and causes type inference blowups at scale (~30-40+ routes) even with skipLibCheck: true.

Fixes posva/unplugin-vue-router#756

Solution

Replace the constraint RouteMap extends RouteMapGeneric with the self-referential RouteMap extends { [K in keyof RouteMap]: RouteRecordInfoGeneric } on all 14 typed route types in route-location.ts.

This preserves the semantic intent ("every value must be a RouteRecordInfoGeneric") without requiring string/symbol index signatures. The default = RouteMapGeneric remains valid.

No runtime changes, types only.

6 alternative solutions were analyzed -- this is the only one that fixes the constraint error while preserving type safety (invalid route names like /nonexistent are still correctly rejected).

Changes

  • packages/router/src/typed-routes/route-location.ts -- 14 constraint sites + 1 import
  • packages/router/__tests__/routeLocation.test-d.ts -- type test using interface (not type) for RouteMap

Tests

  • Added type test using interface (not type) for RouteMap to cover the exact scenario that breaks in real projects. Existing tests only use type aliases, which get implicit index signatures and sidestep the issue.
  • Verified locally:
    • pnpm -C packages/router build -- SUCCESS
    • pnpm -C packages/router test:types -- no new errors
    • pnpm -C packages/router test:unit -- 1483 passed, no regressions, no type errors

Also happy to adjust if maintainers prefer another approach.

Summary by CodeRabbit

  • Tests

    • Added comprehensive type safety tests for route locations with various route map configurations.
  • Refactor

    • Improved generic type constraints in route location helpers to enhance TypeScript type safety and stricter validation of route parameters and paths.

@netlify
Copy link

netlify bot commented Feb 12, 2026

Deploy Preview for vue-router canceled.

Name Link
🔨 Latest commit 43132f9
🔍 Latest deploy log https://app.netlify.com/projects/vue-router/deploys/698e06a245ecd30007327a4a

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

This pull request refines TypeScript generic constraints for route location type helpers. The RouteMap constraint is updated from RouteMapGeneric to a more specific form requiring values to be RouteRecordInfoGeneric, improving type safety. Comprehensive type tests are added to verify interface-based route maps work correctly with the new constraints.

Changes

Cohort / File(s) Summary
Type Tests
packages/router/__tests__/routeLocation.test-d.ts
Added 88 lines of type-level tests verifying that RouteLocationTypedList and related helpers properly accept interface-based RouteMaps with no implicit index signatures, preserving type safety for parameters, names, and paths. Tests include rejection checks for invalid route names.
Type Definitions
packages/router/src/typed-routes/route-location.ts
Updated generic constraints across RouteLocationTyped, RouteLocationNormalizedTyped, RouteLocationAsRelativeTyped, RouteLocationAsPathTyped, RouteLocationAsStringTyped, RouteLocationResolvedTyped, and their TypedList variants. Constraint changed from RouteMap extends RouteMapGeneric to RouteMap extends { [K in keyof RouteMap]: RouteRecordInfoGeneric }. Added import of RouteRecordInfoGeneric.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A rabbit's ode to tighter types:

With constraints now more precise and true,
Our routes align in every hue,
No more ambiguity to confuse—
Each record mapped, no type misuse! 🗺️✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: relaxing the RouteMapGeneric constraint to support interface-based RouteNamedMap types.
Linked Issues check ✅ Passed The PR successfully addresses issue #756 by replacing the RouteMapGeneric constraint with a self-referential constraint that accepts interface-based RouteNamedMap without implicit index signatures.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the type constraint issue: updating 14 constraint sites in route-location.ts and adding type tests to verify the fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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 and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 12, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vue-router@2624

commit: 43132f9

@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.58%. Comparing base (ef327c8) to head (43132f9).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2624   +/-   ##
=======================================
  Coverage   85.58%   85.58%           
=======================================
  Files          86       86           
  Lines        9963     9963           
  Branches     2284     2285    +1     
=======================================
  Hits         8527     8527           
  Misses       1423     1423           
  Partials       13       13           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@posva posva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot! I didn't know we could self reference the type with keyof!

@posva posva merged commit cdf7b44 into vuejs:main Feb 12, 2026
10 checks passed
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.

keyof RouteNamedMap is incompatible with the expected parameter type for router.push()

2 participants