From 92f0d4d5ed06cbc84df6ceb75e811eee7427c349 Mon Sep 17 00:00:00 2001 From: Anoesj Date: Thu, 13 Mar 2025 11:48:24 +0100 Subject: [PATCH 01/10] feat: make typed `useRoute(currentRouteName)` return children route types as well --- packages/docs/guide/advanced/typed-routes.md | 30 ++++++-- packages/playground/src/main.ts | 32 +++++++-- .../router/__tests__/routeLocation.test-d.ts | 71 ++++++++++++++----- packages/router/src/typed-routes/route-map.ts | 17 +++++ packages/router/src/useApi.ts | 15 ++-- .../router/test-dts/typed-routes.test-d.ts | 47 ++++++++++-- 6 files changed, 176 insertions(+), 36 deletions(-) diff --git a/packages/docs/guide/advanced/typed-routes.md b/packages/docs/guide/advanced/typed-routes.md index 5863b94ae..fc626ce3e 100644 --- a/packages/docs/guide/advanced/typed-routes.md +++ b/packages/docs/guide/advanced/typed-routes.md @@ -9,8 +9,8 @@ It's possible to configure the router to have a _map_ of typed routes. While thi Here is an example of how to manually configure typed routes: ```ts -// import the `RouteRecordInfo` type from vue-router to type your routes -import type { RouteRecordInfo } from 'vue-router' +// import the `RouteRecordInfo` and `RouteMeta` type from vue-router to type your routes +import type { RouteRecordInfo, RouteMeta } from 'vue-router' // Define an interface of routes export interface RouteNamedMap { @@ -23,7 +23,11 @@ export interface RouteNamedMap { // these are the raw params. In this case, there are no params allowed Record, // these are the normalized params - Record + Record, + // these are the `meta` fields + RouteMeta, + // this is a union of all children route names + never > // repeat for each route.. // Note you can name them whatever you want @@ -31,19 +35,33 @@ export interface RouteNamedMap { 'named-param', '/:name', { name: string | number }, // raw value - { name: string } // normalized value + { name: string }, // normalized value + RouteMeta, + 'named-param-edit' + > + 'named-param-edit': RouteRecordInfo< + 'named-param-edit', + '/:name/edit', + { name: string | number }, // raw value + { name: string }, // normalized value + RouteMeta, + never > 'article-details': RouteRecordInfo< 'article-details', '/articles/:id+', { id: Array }, - { id: string[] } + { id: string[] }, + RouteMeta, + never > 'not-found': RouteRecordInfo< 'not-found', '/:path(.*)', { path: string }, - { path: string } + { path: string }, + RouteMeta, + never > } diff --git a/packages/playground/src/main.ts b/packages/playground/src/main.ts index eb0f0e1af..844f9bae9 100644 --- a/packages/playground/src/main.ts +++ b/packages/playground/src/main.ts @@ -4,7 +4,12 @@ import type { ComponentPublicInstance } from 'vue' import { router, routerHistory } from './router' import { globalState } from './store' import App from './App.vue' -import { useRoute, type ParamValue, type RouteRecordInfo } from 'vue-router' +import { + useRoute, + type ParamValue, + type RouteRecordInfo, + type RouteMeta, +} from 'vue-router' declare global { interface Window { @@ -32,18 +37,37 @@ app.use(router) window.vm = app.mount('#app') export interface RouteNamedMap { - home: RouteRecordInfo<'home', '/', Record, Record> + home: RouteRecordInfo< + 'home', + '/', + Record, + Record, + RouteMeta, + never + > '/[name]': RouteRecordInfo< '/[name]', '/:name', { name: ParamValue }, - { name: ParamValue } + { name: ParamValue }, + RouteMeta, + '/[name]/edit' + > + '/[name]/edit': RouteRecordInfo< + '/[name]/edit', + '/:name/edit', + { name: ParamValue }, + { name: ParamValue }, + RouteMeta, + never > '/[...path]': RouteRecordInfo< '/[...path]', '/:path(.*)', { path: ParamValue }, - { path: ParamValue } + { path: ParamValue }, + RouteMeta, + never > } diff --git a/packages/router/__tests__/routeLocation.test-d.ts b/packages/router/__tests__/routeLocation.test-d.ts index f228ba823..134d2bbfe 100644 --- a/packages/router/__tests__/routeLocation.test-d.ts +++ b/packages/router/__tests__/routeLocation.test-d.ts @@ -4,6 +4,7 @@ import type { ParamValue, ParamValueZeroOrMore, RouteRecordInfo, + RouteMeta, RouteLocationNormalizedTypedList, } from '../src' @@ -15,25 +16,49 @@ type RouteNamedMap = { '/[other]', '/:other', { other: ParamValue }, - { other: ParamValue } + { other: ParamValue }, + RouteMeta, + never > - '/[name]': RouteRecordInfo< - '/[name]', - '/:name', - { name: ParamValue }, - { name: ParamValue } + '/groups/[gid]': RouteRecordInfo< + '/groups/[gid]', + '/:gid', + { gid: ParamValue }, + { gid: ParamValue }, + RouteMeta, + '/groups/[gid]/users' + > + '/groups/[gid]/users': RouteRecordInfo< + '/groups/[gid]/users', + '/:gid/users', + { gid: ParamValue }, + { gid: ParamValue }, + RouteMeta, + '/groups/[gid]/users/[uid]' + > + '/groups/[gid]/users/[uid]': RouteRecordInfo< + '/groups/[gid]/users/[uid]', + '/:gid/users/:uid', + { gid: ParamValue; uid: ParamValue }, + { gid: ParamValue; uid: ParamValue }, + RouteMeta, + never > '/[...path]': RouteRecordInfo< '/[...path]', '/:path(.*)', { path: ParamValue }, - { path: ParamValue } + { path: ParamValue }, + RouteMeta, + never > '/deep/nesting/works/[[files]]+': RouteRecordInfo< '/deep/nesting/works/[[files]]+', '/deep/nesting/works/:files*', { files?: ParamValueZeroOrMore }, - { files?: ParamValueZeroOrMore } + { files?: ParamValueZeroOrMore }, + RouteMeta, + never > } @@ -50,17 +75,29 @@ describe('Route Location types', () => { ): void function withRoute(...args: unknown[]) {} - withRoute('/[name]', to => { - expectTypeOf(to.params).toEqualTypeOf<{ name: string }>() + withRoute('/groups/[gid]', to => { + expectTypeOf(to.params).toEqualTypeOf<{ gid: string }>() + expectTypeOf(to.params).not.toEqualTypeOf<{ notExisting: string }>() + expectTypeOf(to.params).not.toEqualTypeOf<{ other: string }>() + }) + + withRoute('/groups/[gid]/users', to => { + expectTypeOf(to.params).toEqualTypeOf<{ gid: string }>() + expectTypeOf(to.params).not.toEqualTypeOf<{ gid: string; uid: string }>() + expectTypeOf(to.params).not.toEqualTypeOf<{ other: string }>() + }) + + withRoute('/groups/[gid]/users/[uid]', to => { + expectTypeOf(to.params).toEqualTypeOf<{ gid: string; uid: string }>() expectTypeOf(to.params).not.toEqualTypeOf<{ notExisting: string }>() expectTypeOf(to.params).not.toEqualTypeOf<{ other: string }>() }) - withRoute('/[name]' as keyof RouteNamedMap, to => { + withRoute('/groups/[gid]' as keyof RouteNamedMap, to => { // @ts-expect-error: no all params have this - to.params.name - if (to.name === '/[name]') { - to.params.name + to.params.gid + if (to.name === '/groups/[gid]') { + to.params.gid // @ts-expect-error: no param other to.params.other } @@ -68,12 +105,12 @@ describe('Route Location types', () => { withRoute(to => { // @ts-expect-error: not all params object have a name - to.params.name + to.params.gid // @ts-expect-error: no route named like that if (to.name === '') { } - if (to.name === '/[name]') { - expectTypeOf(to.params).toEqualTypeOf<{ name: string }>() + if (to.name === '/groups/[gid]') { + expectTypeOf(to.params).toEqualTypeOf<{ gid: string }>() // @ts-expect-error: no param other to.params.other } diff --git a/packages/router/src/typed-routes/route-map.ts b/packages/router/src/typed-routes/route-map.ts index b68c72a2f..4285c07ec 100644 --- a/packages/router/src/typed-routes/route-map.ts +++ b/packages/router/src/typed-routes/route-map.ts @@ -18,6 +18,7 @@ export interface RouteRecordInfo< ParamsRaw extends RouteParamsRawGeneric = RouteParamsRawGeneric, Params extends RouteParamsGeneric = RouteParamsGeneric, Meta extends RouteMeta = RouteMeta, + _ChildrenRouteNames extends string | symbol = never, > { name: Name path: Path @@ -39,3 +40,19 @@ export type RouteMap = * Generic version of the `RouteMap`. */ export type RouteMapGeneric = Record + +/** + * Returns a union of route names from children of the route with given route name + */ +export type GetDeepChildrenRouteNames = + RouteMap[T] extends RouteRecordInfo + ? N extends any + ? N | GetDeepChildrenRouteNames + : never + : never + +/** + * Returns a union of given route name and the route names of children of that route + */ +export type RouteNameWithChildren = + RouteMapGeneric extends RouteMap ? T : T | GetDeepChildrenRouteNames diff --git a/packages/router/src/useApi.ts b/packages/router/src/useApi.ts index 988430014..063c06107 100644 --- a/packages/router/src/useApi.ts +++ b/packages/router/src/useApi.ts @@ -1,7 +1,7 @@ import { inject } from 'vue' import { routerKey, routeLocationKey } from './injectionSymbols' import { Router } from './router' -import { RouteMap } from './typed-routes/route-map' +import { RouteMap, RouteNameWithChildren } from './typed-routes/route-map' import { RouteLocationNormalizedLoaded } from './typed-routes' /** @@ -12,12 +12,17 @@ export function useRouter(): Router { return inject(routerKey)! } +type GetRouteLocationNormalizedLoaded = + Name extends any ? RouteLocationNormalizedLoaded : never + /** * Returns the current route location. Equivalent to using `$route` inside * templates. */ -export function useRoute( - _name?: Name -): RouteLocationNormalizedLoaded { - return inject(routeLocationKey)! +export function useRoute< + CurrentRouteName extends keyof RouteMap = keyof RouteMap, +>(_currentRouteName?: CurrentRouteName) { + return inject(routeLocationKey) as GetRouteLocationNormalizedLoaded< + RouteNameWithChildren + > } diff --git a/packages/router/test-dts/typed-routes.test-d.ts b/packages/router/test-dts/typed-routes.test-d.ts index 7f6849818..bc3874873 100644 --- a/packages/router/test-dts/typed-routes.test-d.ts +++ b/packages/router/test-dts/typed-routes.test-d.ts @@ -4,8 +4,11 @@ import { type ParamValue, type ParamValueOneOrMore, type RouteLocationTyped, + type RouteMeta, createRouter, createWebHistory, + useRoute, + RouteLocationNormalizedLoadedTyped, } from './index' // type is needed instead of an interface @@ -15,20 +18,49 @@ export type RouteMap = { '/[...path]', '/:path(.*)', { path: ParamValue }, - { path: ParamValue } + { path: ParamValue }, + RouteMeta, + never > '/[a]': RouteRecordInfo< '/[a]', '/:a', { a: ParamValue }, - { a: ParamValue } + { a: ParamValue }, + RouteMeta, + never + > + '/a': RouteRecordInfo< + '/a', + '/a', + Record, + Record, + RouteMeta, + '/a/b' + > + '/a/b': RouteRecordInfo< + '/a/b', + '/a/b', + Record, + Record, + RouteMeta, + '/a/b/c' + > + '/a/b/c': RouteRecordInfo< + '/a/b/c', + '/a/b/c', + Record, + Record, + RouteMeta, + never > - '/a': RouteRecordInfo<'/a', '/a', Record, Record> '/[id]+': RouteRecordInfo< '/[id]+', '/:id+', { id: ParamValueOneOrMore }, - { id: ParamValueOneOrMore } + { id: ParamValueOneOrMore }, + RouteMeta, + never > } @@ -136,4 +168,11 @@ describe('RouterTyped', () => { return true }) }) + + it('useRoute', () => { + expectTypeOf(useRoute('/[a]')).toEqualTypeOf>(); + expectTypeOf(useRoute('/a')).toEqualTypeOf | RouteLocationNormalizedLoadedTyped | RouteLocationNormalizedLoadedTyped>(); + expectTypeOf(useRoute('/a/b')).toEqualTypeOf | RouteLocationNormalizedLoadedTyped>(); + expectTypeOf(useRoute('/a/b/c')).toEqualTypeOf>(); + }) }) From f907baafffa3077db47912d08aaddbeeebe860e3 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 23 Apr 2025 14:49:11 +0200 Subject: [PATCH 02/10] refactor: longer names in type params --- packages/router/src/typed-routes/route-map.ts | 21 ++++++++++----- .../router/test-dts/typed-routes.test-d.ts | 27 +++++++++++++++---- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/packages/router/src/typed-routes/route-map.ts b/packages/router/src/typed-routes/route-map.ts index 4285c07ec..7d1dd55ce 100644 --- a/packages/router/src/typed-routes/route-map.ts +++ b/packages/router/src/typed-routes/route-map.ts @@ -44,15 +44,24 @@ export type RouteMapGeneric = Record /** * Returns a union of route names from children of the route with given route name */ -export type GetDeepChildrenRouteNames = - RouteMap[T] extends RouteRecordInfo - ? N extends any - ? N | GetDeepChildrenRouteNames +export type GetDeepChildrenRouteNames = + RouteMap[Name] extends RouteRecordInfo< + any, + any, + any, + any, + any, + infer ChildrenNames + > + ? ChildrenNames extends any + ? ChildrenNames | GetDeepChildrenRouteNames : never : never /** * Returns a union of given route name and the route names of children of that route */ -export type RouteNameWithChildren = - RouteMapGeneric extends RouteMap ? T : T | GetDeepChildrenRouteNames +export type RouteNameWithChildren = + RouteMapGeneric extends RouteMap + ? Name + : Name | GetDeepChildrenRouteNames diff --git a/packages/router/test-dts/typed-routes.test-d.ts b/packages/router/test-dts/typed-routes.test-d.ts index bc3874873..06eed1999 100644 --- a/packages/router/test-dts/typed-routes.test-d.ts +++ b/packages/router/test-dts/typed-routes.test-d.ts @@ -8,7 +8,7 @@ import { createRouter, createWebHistory, useRoute, - RouteLocationNormalizedLoadedTyped, + RouteLocationNormalizedLoadedTypedList, } from './index' // type is needed instead of an interface @@ -64,6 +64,15 @@ export type RouteMap = { > } +// the type allows for type params to distribute types: +// RouteLocationNormalizedLoadedLoaded<'/[a]' | '/'> will become RouteLocationNormalizedLoadedTyped['/[a]'] | RouteLocationTypedList['/'] +// it's closer to what the end users uses but with the RouteMap type fixed so it doesn't +// pollute globals +type RouteLocationNormalizedLoaded< + Name extends keyof RouteMap = keyof RouteMap, +> = RouteLocationNormalizedLoadedTypedList[Name] +// type Test = RouteLocationNormalizedLoaded<'/a' | '/a/b' | '/a/b/c'> + declare module './index' { interface TypesConfig { RouteNamedMap: RouteMap @@ -170,9 +179,17 @@ describe('RouterTyped', () => { }) it('useRoute', () => { - expectTypeOf(useRoute('/[a]')).toEqualTypeOf>(); - expectTypeOf(useRoute('/a')).toEqualTypeOf | RouteLocationNormalizedLoadedTyped | RouteLocationNormalizedLoadedTyped>(); - expectTypeOf(useRoute('/a/b')).toEqualTypeOf | RouteLocationNormalizedLoadedTyped>(); - expectTypeOf(useRoute('/a/b/c')).toEqualTypeOf>(); + expectTypeOf(useRoute('/[a]')).toEqualTypeOf< + RouteLocationNormalizedLoaded<'/[a]'> + >() + expectTypeOf(useRoute('/a')).toEqualTypeOf< + RouteLocationNormalizedLoaded<'/a' | '/a/b' | '/a/b/c'> + >() + expectTypeOf(useRoute('/a/b')).toEqualTypeOf< + RouteLocationNormalizedLoaded<'/a/b' | '/a/b/c'> + >() + expectTypeOf(useRoute('/a/b/c')).toEqualTypeOf< + RouteLocationNormalizedLoaded<'/a/b/c'> + >() }) }) From 15aa27280d6e19610ed04171dab6b8b828903ec5 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 23 Apr 2025 15:17:01 +0200 Subject: [PATCH 03/10] refactor: reduce types --- packages/router/src/typed-routes/route-map.ts | 28 ++----------------- packages/router/src/useApi.ts | 15 ++++------ .../router/test-dts/typed-routes.test-d.ts | 2 +- 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/packages/router/src/typed-routes/route-map.ts b/packages/router/src/typed-routes/route-map.ts index 7d1dd55ce..1d4db72e9 100644 --- a/packages/router/src/typed-routes/route-map.ts +++ b/packages/router/src/typed-routes/route-map.ts @@ -18,7 +18,7 @@ export interface RouteRecordInfo< ParamsRaw extends RouteParamsRawGeneric = RouteParamsRawGeneric, Params extends RouteParamsGeneric = RouteParamsGeneric, Meta extends RouteMeta = RouteMeta, - _ChildrenRouteNames extends string | symbol = never, + ChildrenNames extends string | symbol | never = never | string | symbol, > { name: Name path: Path @@ -26,6 +26,7 @@ export interface RouteRecordInfo< params: Params // TODO: implement meta with a defineRoute macro meta: Meta + childrenNames: ChildrenNames } /** @@ -40,28 +41,3 @@ export type RouteMap = * Generic version of the `RouteMap`. */ export type RouteMapGeneric = Record - -/** - * Returns a union of route names from children of the route with given route name - */ -export type GetDeepChildrenRouteNames = - RouteMap[Name] extends RouteRecordInfo< - any, - any, - any, - any, - any, - infer ChildrenNames - > - ? ChildrenNames extends any - ? ChildrenNames | GetDeepChildrenRouteNames - : never - : never - -/** - * Returns a union of given route name and the route names of children of that route - */ -export type RouteNameWithChildren = - RouteMapGeneric extends RouteMap - ? Name - : Name | GetDeepChildrenRouteNames diff --git a/packages/router/src/useApi.ts b/packages/router/src/useApi.ts index 063c06107..36930a962 100644 --- a/packages/router/src/useApi.ts +++ b/packages/router/src/useApi.ts @@ -1,7 +1,7 @@ import { inject } from 'vue' import { routerKey, routeLocationKey } from './injectionSymbols' import { Router } from './router' -import { RouteMap, RouteNameWithChildren } from './typed-routes/route-map' +import { RouteMap } from './typed-routes/route-map' import { RouteLocationNormalizedLoaded } from './typed-routes' /** @@ -12,17 +12,14 @@ export function useRouter(): Router { return inject(routerKey)! } -type GetRouteLocationNormalizedLoaded = - Name extends any ? RouteLocationNormalizedLoaded : never - /** * Returns the current route location. Equivalent to using `$route` inside * templates. */ -export function useRoute< - CurrentRouteName extends keyof RouteMap = keyof RouteMap, ->(_currentRouteName?: CurrentRouteName) { - return inject(routeLocationKey) as GetRouteLocationNormalizedLoaded< - RouteNameWithChildren +export function useRoute( + _name?: Name +) { + return inject(routeLocationKey) as RouteLocationNormalizedLoaded< + Name | RouteMap[Name]['childrenNames'] > } diff --git a/packages/router/test-dts/typed-routes.test-d.ts b/packages/router/test-dts/typed-routes.test-d.ts index 06eed1999..2c87b984d 100644 --- a/packages/router/test-dts/typed-routes.test-d.ts +++ b/packages/router/test-dts/typed-routes.test-d.ts @@ -36,7 +36,7 @@ export type RouteMap = { Record, Record, RouteMeta, - '/a/b' + '/a/b' | '/a/b/c' > '/a/b': RouteRecordInfo< '/a/b', From 04c6f1a86b62a1e2fcaa1920ed8c844cdbef768b Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 23 Apr 2025 15:26:41 +0200 Subject: [PATCH 04/10] test: add back test with a param directly --- packages/router/__tests__/routeLocation.test-d.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/router/__tests__/routeLocation.test-d.ts b/packages/router/__tests__/routeLocation.test-d.ts index 134d2bbfe..d6b74506d 100644 --- a/packages/router/__tests__/routeLocation.test-d.ts +++ b/packages/router/__tests__/routeLocation.test-d.ts @@ -8,7 +8,7 @@ import type { RouteLocationNormalizedTypedList, } from '../src' -// TODO: could we move this to an .d.ts file that is only loaded for tests? +// NOTE: A type allows us to make it work only in this test file // https://github.com/microsoft/TypeScript/issues/15300 type RouteNamedMap = { home: RouteRecordInfo<'/', '/', Record, Record> @@ -73,7 +73,13 @@ describe('Route Location types', () => { name: Name, fn: (to: RouteLocationNormalizedTypedList[Name]) => void ): void - function withRoute(...args: unknown[]) {} + function withRoute<_Name extends RouteRecordName>(..._args: unknown[]) {} + + withRoute('/[other]', to => { + expectTypeOf(to.params).toEqualTypeOf<{ other: string }>() + expectTypeOf(to.params).not.toEqualTypeOf<{ gid: string }>() + expectTypeOf(to.params).not.toEqualTypeOf<{ notExisting: string }>() + }) withRoute('/groups/[gid]', to => { expectTypeOf(to.params).toEqualTypeOf<{ gid: string }>() From 86864b4120c3734893fec138045fc9c300350b66 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 23 Apr 2025 18:56:36 +0200 Subject: [PATCH 05/10] types: generic route record info --- packages/router/__tests__/routeLocation.test-d.ts | 2 +- packages/router/src/typed-routes/route-map.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/router/__tests__/routeLocation.test-d.ts b/packages/router/__tests__/routeLocation.test-d.ts index d6b74506d..2672b14d2 100644 --- a/packages/router/__tests__/routeLocation.test-d.ts +++ b/packages/router/__tests__/routeLocation.test-d.ts @@ -26,7 +26,7 @@ type RouteNamedMap = { { gid: ParamValue }, { gid: ParamValue }, RouteMeta, - '/groups/[gid]/users' + '/groups/[gid]/users' | '/groups/[gid]/users/[uid]' > '/groups/[gid]/users': RouteRecordInfo< '/groups/[gid]/users', diff --git a/packages/router/src/typed-routes/route-map.ts b/packages/router/src/typed-routes/route-map.ts index 1d4db72e9..a465cc52f 100644 --- a/packages/router/src/typed-routes/route-map.ts +++ b/packages/router/src/typed-routes/route-map.ts @@ -18,7 +18,7 @@ export interface RouteRecordInfo< ParamsRaw extends RouteParamsRawGeneric = RouteParamsRawGeneric, Params extends RouteParamsGeneric = RouteParamsGeneric, Meta extends RouteMeta = RouteMeta, - ChildrenNames extends string | symbol | never = never | string | symbol, + ChildrenNames extends string | symbol = never, > { name: Name path: Path @@ -29,6 +29,15 @@ export interface RouteRecordInfo< childrenNames: ChildrenNames } +export type RouteRecordInfoGeneric = RouteRecordInfo< + string | symbol, + string, + RouteParamsRawGeneric, + RouteParamsGeneric, + RouteMeta, + string | symbol +> + /** * Convenience type to get the typed RouteMap or a generic one if not provided. It is extracted from the {@link TypesConfig} if it exists, it becomes {@link RouteMapGeneric} otherwise. */ @@ -40,4 +49,4 @@ export type RouteMap = /** * Generic version of the `RouteMap`. */ -export type RouteMapGeneric = Record +export type RouteMapGeneric = Record From 88aa1eaf0eacbaeea83773e6518eb79532e65ec6 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 25 Apr 2025 09:51:39 +0200 Subject: [PATCH 06/10] fix: remove unused Meta type param from RouteRecordInfo --- .../router/__tests__/routeLocation.test-d.ts | 7 ------- packages/router/src/typed-routes/route-map.ts | 17 ++++++++--------- packages/router/src/types/index.ts | 2 +- packages/router/test-dts/typed-routes.test-d.ts | 7 ------- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/packages/router/__tests__/routeLocation.test-d.ts b/packages/router/__tests__/routeLocation.test-d.ts index 2672b14d2..423f20a29 100644 --- a/packages/router/__tests__/routeLocation.test-d.ts +++ b/packages/router/__tests__/routeLocation.test-d.ts @@ -4,7 +4,6 @@ import type { ParamValue, ParamValueZeroOrMore, RouteRecordInfo, - RouteMeta, RouteLocationNormalizedTypedList, } from '../src' @@ -17,7 +16,6 @@ type RouteNamedMap = { '/:other', { other: ParamValue }, { other: ParamValue }, - RouteMeta, never > '/groups/[gid]': RouteRecordInfo< @@ -25,7 +23,6 @@ type RouteNamedMap = { '/:gid', { gid: ParamValue }, { gid: ParamValue }, - RouteMeta, '/groups/[gid]/users' | '/groups/[gid]/users/[uid]' > '/groups/[gid]/users': RouteRecordInfo< @@ -33,7 +30,6 @@ type RouteNamedMap = { '/:gid/users', { gid: ParamValue }, { gid: ParamValue }, - RouteMeta, '/groups/[gid]/users/[uid]' > '/groups/[gid]/users/[uid]': RouteRecordInfo< @@ -41,7 +37,6 @@ type RouteNamedMap = { '/:gid/users/:uid', { gid: ParamValue; uid: ParamValue }, { gid: ParamValue; uid: ParamValue }, - RouteMeta, never > '/[...path]': RouteRecordInfo< @@ -49,7 +44,6 @@ type RouteNamedMap = { '/:path(.*)', { path: ParamValue }, { path: ParamValue }, - RouteMeta, never > '/deep/nesting/works/[[files]]+': RouteRecordInfo< @@ -57,7 +51,6 @@ type RouteNamedMap = { '/deep/nesting/works/:files*', { files?: ParamValueZeroOrMore }, { files?: ParamValueZeroOrMore }, - RouteMeta, never > } diff --git a/packages/router/src/typed-routes/route-map.ts b/packages/router/src/typed-routes/route-map.ts index a465cc52f..7a7f0a2ef 100644 --- a/packages/router/src/typed-routes/route-map.ts +++ b/packages/router/src/typed-routes/route-map.ts @@ -1,9 +1,5 @@ import type { TypesConfig } from '../config' -import type { - RouteMeta, - RouteParamsGeneric, - RouteParamsRawGeneric, -} from '../types' +import type { RouteParamsGeneric, RouteParamsRawGeneric } from '../types' import type { RouteRecord } from '../matcher/types' /** @@ -17,16 +13,20 @@ export interface RouteRecordInfo< // TODO: could probably be inferred from the Params ParamsRaw extends RouteParamsRawGeneric = RouteParamsRawGeneric, Params extends RouteParamsGeneric = RouteParamsGeneric, - Meta extends RouteMeta = RouteMeta, + // NOTE: this is the only type param that feels wrong because its default + // value is the default value to avoid breaking changes but it should be the + // generic version by default instead (string | symbol) ChildrenNames extends string | symbol = never, + // TODO: implement meta with a defineRoute macro + // Meta extends RouteMeta = RouteMeta, > { name: Name path: Path paramsRaw: ParamsRaw params: Params - // TODO: implement meta with a defineRoute macro - meta: Meta childrenNames: ChildrenNames + // TODO: implement meta with a defineRoute macro + // meta: Meta } export type RouteRecordInfoGeneric = RouteRecordInfo< @@ -34,7 +34,6 @@ export type RouteRecordInfoGeneric = RouteRecordInfo< string, RouteParamsRawGeneric, RouteParamsGeneric, - RouteMeta, string | symbol > diff --git a/packages/router/src/types/index.ts b/packages/router/src/types/index.ts index c06643956..bf8f7fb6c 100644 --- a/packages/router/src/types/index.ts +++ b/packages/router/src/types/index.ts @@ -257,7 +257,7 @@ export interface _RouteRecordBase extends PathParserOptions { * } * ``` */ -export interface RouteMeta extends Record {} +export interface RouteMeta extends Record {} /** * Route Record defining one single component with the `component` option. diff --git a/packages/router/test-dts/typed-routes.test-d.ts b/packages/router/test-dts/typed-routes.test-d.ts index 2c87b984d..c520bdb11 100644 --- a/packages/router/test-dts/typed-routes.test-d.ts +++ b/packages/router/test-dts/typed-routes.test-d.ts @@ -4,7 +4,6 @@ import { type ParamValue, type ParamValueOneOrMore, type RouteLocationTyped, - type RouteMeta, createRouter, createWebHistory, useRoute, @@ -19,7 +18,6 @@ export type RouteMap = { '/:path(.*)', { path: ParamValue }, { path: ParamValue }, - RouteMeta, never > '/[a]': RouteRecordInfo< @@ -27,7 +25,6 @@ export type RouteMap = { '/:a', { a: ParamValue }, { a: ParamValue }, - RouteMeta, never > '/a': RouteRecordInfo< @@ -35,7 +32,6 @@ export type RouteMap = { '/a', Record, Record, - RouteMeta, '/a/b' | '/a/b/c' > '/a/b': RouteRecordInfo< @@ -43,7 +39,6 @@ export type RouteMap = { '/a/b', Record, Record, - RouteMeta, '/a/b/c' > '/a/b/c': RouteRecordInfo< @@ -51,7 +46,6 @@ export type RouteMap = { '/a/b/c', Record, Record, - RouteMeta, never > '/[id]+': RouteRecordInfo< @@ -59,7 +53,6 @@ export type RouteMap = { '/:id+', { id: ParamValueOneOrMore }, { id: ParamValueOneOrMore }, - RouteMeta, never > } From e433558e8d88db81e6207a894daf189f837772eb Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 25 Apr 2025 09:52:24 +0200 Subject: [PATCH 07/10] docs: remove old unused RouteMeta --- packages/docs/guide/advanced/typed-routes.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/docs/guide/advanced/typed-routes.md b/packages/docs/guide/advanced/typed-routes.md index fc626ce3e..82838493f 100644 --- a/packages/docs/guide/advanced/typed-routes.md +++ b/packages/docs/guide/advanced/typed-routes.md @@ -9,8 +9,8 @@ It's possible to configure the router to have a _map_ of typed routes. While thi Here is an example of how to manually configure typed routes: ```ts -// import the `RouteRecordInfo` and `RouteMeta` type from vue-router to type your routes -import type { RouteRecordInfo, RouteMeta } from 'vue-router' +// import the `RouteRecordInfo` type from vue-router to type your routes +import type { RouteRecordInfo } from 'vue-router' // Define an interface of routes export interface RouteNamedMap { @@ -24,8 +24,6 @@ export interface RouteNamedMap { Record, // these are the normalized params Record, - // these are the `meta` fields - RouteMeta, // this is a union of all children route names never > @@ -36,7 +34,6 @@ export interface RouteNamedMap { '/:name', { name: string | number }, // raw value { name: string }, // normalized value - RouteMeta, 'named-param-edit' > 'named-param-edit': RouteRecordInfo< @@ -44,7 +41,6 @@ export interface RouteNamedMap { '/:name/edit', { name: string | number }, // raw value { name: string }, // normalized value - RouteMeta, never > 'article-details': RouteRecordInfo< @@ -52,7 +48,6 @@ export interface RouteNamedMap { '/articles/:id+', { id: Array }, { id: string[] }, - RouteMeta, never > 'not-found': RouteRecordInfo< @@ -60,7 +55,6 @@ export interface RouteNamedMap { '/:path(.*)', { path: string }, { path: string }, - RouteMeta, never > } From 676b8ad90e0e581506be93ba4812d3a7f6fdd988 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 25 Apr 2025 09:52:53 +0200 Subject: [PATCH 08/10] chore: remove unused type param RouteMeta --- packages/playground/src/main.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/playground/src/main.ts b/packages/playground/src/main.ts index 844f9bae9..1df834422 100644 --- a/packages/playground/src/main.ts +++ b/packages/playground/src/main.ts @@ -4,12 +4,7 @@ import type { ComponentPublicInstance } from 'vue' import { router, routerHistory } from './router' import { globalState } from './store' import App from './App.vue' -import { - useRoute, - type ParamValue, - type RouteRecordInfo, - type RouteMeta, -} from 'vue-router' +import { useRoute, type ParamValue, type RouteRecordInfo } from 'vue-router' declare global { interface Window { @@ -42,7 +37,6 @@ export interface RouteNamedMap { '/', Record, Record, - RouteMeta, never > '/[name]': RouteRecordInfo< @@ -50,7 +44,6 @@ export interface RouteNamedMap { '/:name', { name: ParamValue }, { name: ParamValue }, - RouteMeta, '/[name]/edit' > '/[name]/edit': RouteRecordInfo< @@ -58,7 +51,6 @@ export interface RouteNamedMap { '/:name/edit', { name: ParamValue }, { name: ParamValue }, - RouteMeta, never > '/[...path]': RouteRecordInfo< @@ -66,7 +58,6 @@ export interface RouteNamedMap { '/:path(.*)', { path: ParamValue }, { path: ParamValue }, - RouteMeta, never > } From cf5349fab86ef753873e1bd52a9a2a949fe5f22d Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 25 Apr 2025 09:55:27 +0200 Subject: [PATCH 09/10] chore: better docs --- packages/docs/guide/advanced/typed-routes.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/docs/guide/advanced/typed-routes.md b/packages/docs/guide/advanced/typed-routes.md index 82838493f..f72608494 100644 --- a/packages/docs/guide/advanced/typed-routes.md +++ b/packages/docs/guide/advanced/typed-routes.md @@ -20,27 +20,28 @@ export interface RouteNamedMap { 'home', // this is the path, it will appear in autocompletion '/', - // these are the raw params. In this case, there are no params allowed + // these are the raw params (what can be passed to router.push() and RouterLink's "to" prop) + // In this case, there are no params allowed Record, - // these are the normalized params + // these are the normalized params (what you get from useRoute()) Record, - // this is a union of all children route names + // this is a union of all children route names, in this case, there are none never > - // repeat for each route.. + // repeat for each route... // Note you can name them whatever you want 'named-param': RouteRecordInfo< 'named-param', '/:name', - { name: string | number }, // raw value - { name: string }, // normalized value + { name: string | number }, // Allows string or number + { name: string }, // but always returns a string from the URL 'named-param-edit' > 'named-param-edit': RouteRecordInfo< 'named-param-edit', '/:name/edit', - { name: string | number }, // raw value - { name: string }, // normalized value + { name: string | number }, // we also include parent params + { name: string }, never > 'article-details': RouteRecordInfo< From bc9cea21614a555eea9538778136c76043fe5bf3 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 25 Apr 2025 09:58:15 +0200 Subject: [PATCH 10/10] types: expose generic version --- packages/router/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts index 2a62ad156..2b27d8329 100644 --- a/packages/router/src/index.ts +++ b/packages/router/src/index.ts @@ -113,6 +113,7 @@ export type { RouteLocationAsPathTypedList, // route records + RouteRecordInfoGeneric, RouteRecordInfo, RouteRecordNameGeneric, RouteRecordName,