Skip to content

Commit d02d19f

Browse files
committed
feat: add typed router link
1 parent 1aa0ea1 commit d02d19f

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

packages/playground/src/router.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createRouter, createWebHistory, RouterView } from 'vue-router'
2+
import type { RouterLinkTyped } from 'vue-router'
23
import Home from './views/Home.vue'
34
import Nested from './views/Nested.vue'
45
import NestedWithId from './views/NestedWithId.vue'
@@ -189,6 +190,12 @@ declare module 'vue-router' {
189190
}
190191
}
191192

193+
declare module 'vue' {
194+
interface GlobalComponents {
195+
RouterLink: RouterLinkTyped<typeof router>
196+
}
197+
}
198+
192199
const delay = (t: number) => new Promise(resolve => setTimeout(resolve, t))
193200

194201
// remove trailing slashes

packages/router/src/RouterLink.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,35 @@ import {
3131
VueUseOptions,
3232
RouteLocation,
3333
RouteLocationNormalized,
34+
RouteLocationPathRaw,
35+
RouteLocationString,
36+
RouteLocationNamedRaw,
3437
} from './types'
3538
import { isSameRouteLocationParams, isSameRouteRecord } from './___location'
3639
import { routerKey, routeLocationKey } from './injectionSymbols'
3740
import { RouteRecord } from './matcher/types'
3841
import { NavigationFailure } from './errors'
3942
import { isArray, isBrowser, noop } from './utils'
43+
import type { Router } from './router'
44+
import { RouteNamedMap, RouteStaticPathMap } from './types/named'
4045

41-
export interface RouterLinkOptions {
46+
export interface RouterLinkOptions<
47+
Routes extends RouteLocationRaw = RouteLocationRaw
48+
> {
4249
/**
4350
* Route Location the link should navigate to when clicked on.
4451
*/
45-
to: RouteLocationRaw
52+
to: Routes
4653
/**
4754
* Calls `router.replace` instead of `router.push`.
4855
*/
4956
replace?: boolean
5057
// TODO: refactor using extra options allowed in router.push. Needs RFC
5158
}
5259

53-
export interface RouterLinkProps extends RouterLinkOptions {
60+
export interface RouterLinkProps<
61+
Routes extends RouteLocationRaw = RouteLocationRaw
62+
> extends RouterLinkOptions<Routes> {
5463
/**
5564
* Whether RouterLink should not wrap its content in an `a` tag. Useful when
5665
* using `v-slot` to create a custom RouterLink
@@ -251,12 +260,18 @@ export const RouterLinkImpl = /*#__PURE__*/ defineComponent({
251260
/**
252261
* Component to render a link that triggers a navigation on click.
253262
*/
254-
export const RouterLink = RouterLinkImpl as unknown as {
263+
export const RouterLink = RouterLinkImpl as unknown as RouterLinkTyped
264+
265+
export interface RouterLinkTyped<R extends Router = Router> {
255266
new (): {
256267
$props: AllowedComponentProps &
257268
ComponentCustomProps &
258269
VNodeProps &
259-
RouterLinkProps
270+
RouterLinkProps<
271+
| RouteLocationNamedRaw<RouteNamedMap<R['options']['routes']>>
272+
| RouteLocationString<RouteStaticPathMap<R['options']['routes']>>
273+
| RouteLocationPathRaw<RouteStaticPathMap<R['options']['routes']>>
274+
>
260275

261276
$slots: {
262277
default: (arg: UnwrapRef<ReturnType<typeof useLink>>) => VNode[]

packages/router/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ export {
9999
loadRouteLocation,
100100
} from './navigationGuards'
101101
export { RouterLink, useLink } from './RouterLink'
102-
export type { RouterLinkProps, UseLinkOptions } from './RouterLink'
102+
export type {
103+
RouterLinkProps,
104+
UseLinkOptions,
105+
RouterLinkTyped,
106+
} from './RouterLink'
103107
export { RouterView } from './RouterView'
104108
export type { RouterViewProps } from './RouterView'
105109

0 commit comments

Comments
 (0)