Remove the deprecated component, components and props options - #800
Open
pleek91 wants to merge 23 commits into
Open
Remove the deprecated component, components and props options#800pleek91 wants to merge 23 commits into
pleek91 wants to merge 23 commits into
Conversation
pleek91
marked this pull request as ready for review
July 30, 2026 15:58
pleek91
force-pushed
the
remove-deprecated-views
branch
from
July 30, 2026 16:33
53a0204 to
51caa6d
Compare
Views were spread across three parallel records — components, props, and
prefetch — with props further split between a bare getter for a lone unnamed
view and a record once a named view was added. Merge them into one record of
{ component, props, prefetch } keyed by view name.
The props argument's two shapes are normalized once in createRouteViews, so
nothing downstream deals with them. That removes ViewProps, isBareProps,
isPropsRecord, toPropsRecord, addProps, addPrefetch, and collapses
getComponentProps to a single map.
The two duplicate parent props derivations — one for the createRoute props
argument, one for addView — are now a single shared ViewsPropsReturnType.
A lone unnamed view still gives its props directly rather than under a
'default' key, so the public shape of parent.props is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Assertions targeted the old props slot, which held either a bare getter or a
record. They now target the views record, so a lone unnamed view reads as
{ default: RouteView<getter> } rather than the getter alone.
Adding a view without a getter no longer adds a key to the type. It used to
add one carrying never, which disagreed with the createRoute path, where a
component with no props produced an empty record.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each entry was { id, views }, so reaching a view read route.views[depth].views
.sidebar. The id was documented as always equal to matches[depth].id, and every
consumer already had the depth or the match in hand, so it was duplicated data
paying for a level of nesting.
The entry is now the record itself: route.views[depth].sidebar. Consumers take
the id from matches, which also removes the RouteViews unwrapping the parent
props types had to do.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Views were a second tuple indexed in parallel with matches, which the two had to be kept aligned by hand. That alignment is what made getParentContext read the wrong parent: it took matches.at(-2) and views.at(-2) independently. Views now hang off the match they belong to, so there is no alignment left to get wrong and route.matches shows names, meta and view types together. matched is derived from the last match by withMatched, which everything that builds or rebuilds a route goes through. The Route type already described it as LastInArray<TMatches>, so this makes the runtime agree with the type rather than storing it twice. combineRoutes no longer reads child.matched either, so matched is only ever an output. Views were also the one part of a route that was not markRaw, so passing through reactive() in createRouterRoute turned every component into a reactive proxy, which Vue warns about. They are inside the markRaw match now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
matched on a route definition meant nothing — nothing has been matched yet, it was just the last of the chain. Every reader was already working with a resolved or router route, and ResolvedRoute declares its own fields rather than extending Route, so it can derive matched from matches instead of forwarding it. It is computed once in createResolvedRoute, which runs after every addView, so there is no window where it can disagree with matches. That removes the need for withMatched and the derivation it was doing at all four construction sites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each match kept the parent option, which is a whole Route including its chained methods, so a child's match embedded the full type of every ancestor above it. Nothing reads parent off a match, and matches already carries the ancestors it describes. Also drops the two matched.meta type tests, which became duplicates of the matches[number].meta block below them, and points the router immutability assertion at matches.at(-1) rather than a route definition. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
addView left a view out of the type entirely when it had no props getter, so a route with a default and a sidebar view alongside one that took props showed only the one with props. That was fine while the views type existed purely to type parent props, but it is now the views a user sees on route.matches, so it should describe every view. A view without a getter reads as RouteView, and parent props still only sees views that have one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every addView rebuilt the route by re-deriving its url from the previous route
type, so chaining nested one inside the last: three calls produced three layers
of WithViewProps, each carrying the views accumulated so far. A route ended up
describing its own history rather than its current shape.
RouteAddView and RouteWithMethods now take the url and matches, so adding a view
passes the url through untouched and only replaces the last match's views. The
result is the same shape whether one view was added or ten, and WithViewProps is
gone along with the Pick that recovered the url.
Also rewrites the route shape type test. It asserted hooks against the route
type itself, which only held for createRoute({}) because empty options collapse
to a bare Route — it failed as soon as a view was added, though every member was
present. It now asserts the members a route has, against a plain route and each
addView shape, since those should not differ.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
createRoute described its return as a four way intersection of the route with each group of methods, while a route rebuilt by addView was one alias. Both are now RouteWithMethods, so a route reads the same however it was built. The hooks were the reason this needed the long form: they took the context extracted from the options rather than from the route. Context is derived from matches, so the route carries it either way. Also stops PropsToViews distributing over its type parameter, so never cannot collapse a views record to never. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The caller assembled the match around a views helper and reapplied markRaw itself, which left the reason for the marking away from the code that needed it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A child is given a parent's props directly when the unnamed view is the only one with props, and keyed by view name otherwise. Views used to store that distinction, so reading it was a matter of asking whether props was a function or a record. They are always keyed by name now, so the question is asked of them instead — behind guards that say which case they describe, as the old ones did. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Indexing the last match said it was always there. A route without matches is a broken route, so say so instead of typing around it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
isWithComponentProps and isWithComponentPropsRecord told a bare props getter apart from a record of them, which is how a parent's props shape used to be read. Views are keyed by name now, so nothing asks that question of the options. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pleek91
force-pushed
the
remove-deprecated-views
branch
from
July 30, 2026 16:34
51caa6d to
1156f5d
Compare
A view only needs the props type, not the signature that produced it, so
RouteView holds the getter's return type. Reading parent props back is a
single infer, and views read as RouteView<{ foo: string }> in tooltips.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pleek91
force-pushed
the
remove-deprecated-views
branch
from
July 30, 2026 17:22
1156f5d to
b83562d
Compare
The existing test gave the parent no views at all, which reports undefined without ever reading a view. This one relies on RouteView's default, which is what encodes "this view has no props". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every view comes from addView now, so nothing seeds views from options. That takes the component and components options with it, along with the props argument and the types that existed to describe it: CreateRouteProps, RoutePropsRecord, RouterViewPropsGetter, CreateRouteWithProps, PropsToViews, WithoutComponents, isWithComponent and isWithComponents. createRouteViews had nothing left to build, so a route starts with no views and the file keeps only the default view name and the two view guards. Tests still use the removed syntax and are not converted here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Tests that named a component in options or passed a props argument now add a view instead. Where a component was left out for brevity, one is passed, since props without a component is no longer something the router supports. The deprecated props argument had its own tests for whether the argument was required and what shape it took. addView covers each of those, so they are removed rather than rewritten. Rejections build their route with addView too, and one test read a component off the matched route, which views carry now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Leaving component and components out of the options type did not stop the old syntax type checking — extra properties are allowed when inferring against it, so a route naming a component silently came out with no views. Several tests were in that state and only a render assertion caught it. Declaring them means passing one is a mismatch rather than an extra property. The declared type is the guidance, so the error says what to do instead of naming a type nobody wrote. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
They only exist to catch the old syntax, so they should go at the next major version once nobody is upgrading past them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Props are now only declared through addView, so move the props type tests there and drop the duplicates. Also removes the two "backwards compatibility" tests, which no longer test the deprecated options. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pleek91
force-pushed
the
remove-deprecated-views
branch
from
July 30, 2026 17:53
b83562d to
69d4261
Compare
stackoverfloweth
approved these changes
Jul 30, 2026
Member
Author
|
@stackoverfloweth not going to merge this until after we do the next minor release so we have one version where both are supported for users to use as a migration version. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Removes the deprecated
componentandcomponentsoptions and the props argument. Views are added withaddView.Breaking change
Named views move from
componentsto a name per view.Passing props without a component is no longer supported. A view needs a component to render.
Passing
componentorcomponentsis now an error rather than being ignored, so the compiler points at anything left to migrate.