]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat: add typed router link
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 15 Jun 2022 16:37:12 +0000 (18:37 +0200)
committerEduardo San Martin Morote <posva@users.noreply.github.com>
Thu, 30 Jun 2022 07:59:00 +0000 (09:59 +0200)
packages/playground/src/router.ts
packages/router/src/RouterLink.ts
packages/router/src/index.ts

index ca88c525b903a702a669eec70768708a9284df3d..836edad6908b8cec1e915485eeeeacfeb2a5d726 100644 (file)
@@ -1,4 +1,5 @@
 import { createRouter, createWebHistory, RouterView } from 'vue-router'
+import type { RouterLinkTyped } from 'vue-router'
 import Home from './views/Home.vue'
 import Nested from './views/Nested.vue'
 import NestedWithId from './views/NestedWithId.vue'
@@ -189,6 +190,12 @@ declare module 'vue-router' {
   }
 }
 
+declare module 'vue' {
+  interface GlobalComponents {
+    RouterLink: RouterLinkTyped<typeof router>
+  }
+}
+
 const delay = (t: number) => new Promise(resolve => setTimeout(resolve, t))
 
 // remove trailing slashes
index bc28001f6a3f663c0b44e61ed35070a16b3a7477..b82f75e26b23978d736aace00e9a5fd4dfad2f1c 100644 (file)
@@ -31,18 +31,25 @@ import {
   VueUseOptions,
   RouteLocation,
   RouteLocationNormalized,
+  RouteLocationPathRaw,
+  RouteLocationString,
+  RouteLocationNamedRaw,
 } from './types'
 import { isSameRouteLocationParams, isSameRouteRecord } from './location'
 import { routerKey, routeLocationKey } from './injectionSymbols'
 import { RouteRecord } from './matcher/types'
 import { NavigationFailure } from './errors'
 import { isArray, isBrowser, noop } from './utils'
+import type { Router } from './router'
+import { RouteNamedMap, RouteStaticPathMap } from './types/named'
 
-export interface RouterLinkOptions {
+export interface RouterLinkOptions<
+  Routes extends RouteLocationRaw = RouteLocationRaw
+> {
   /**
    * Route Location the link should navigate to when clicked on.
    */
-  to: RouteLocationRaw
+  to: Routes
   /**
    * Calls `router.replace` instead of `router.push`.
    */
@@ -50,7 +57,9 @@ export interface RouterLinkOptions {
   // TODO: refactor using extra options allowed in router.push. Needs RFC
 }
 
-export interface RouterLinkProps extends RouterLinkOptions {
+export interface RouterLinkProps<
+  Routes extends RouteLocationRaw = RouteLocationRaw
+> extends RouterLinkOptions<Routes> {
   /**
    * Whether RouterLink should not wrap its content in an `a` tag. Useful when
    * using `v-slot` to create a custom RouterLink
@@ -251,12 +260,18 @@ export const RouterLinkImpl = /*#__PURE__*/ defineComponent({
 /**
  * Component to render a link that triggers a navigation on click.
  */
-export const RouterLink = RouterLinkImpl as unknown as {
+export const RouterLink = RouterLinkImpl as unknown as RouterLinkTyped
+
+export interface RouterLinkTyped<R extends Router = Router> {
   new (): {
     $props: AllowedComponentProps &
       ComponentCustomProps &
       VNodeProps &
-      RouterLinkProps
+      RouterLinkProps<
+        | RouteLocationNamedRaw<RouteNamedMap<R['options']['routes']>>
+        | RouteLocationString<RouteStaticPathMap<R['options']['routes']>>
+        | RouteLocationPathRaw<RouteStaticPathMap<R['options']['routes']>>
+      >
 
     $slots: {
       default: (arg: UnwrapRef<ReturnType<typeof useLink>>) => VNode[]
index 0502e1ee6703cc5d35212aece1d8a9649e5cc9ec..c93fe522b28293182e22f34c49c7aa66a4f20968 100644 (file)
@@ -99,7 +99,11 @@ export {
   loadRouteLocation,
 } from './navigationGuards'
 export { RouterLink, useLink } from './RouterLink'
-export type { RouterLinkProps, UseLinkOptions } from './RouterLink'
+export type {
+  RouterLinkProps,
+  UseLinkOptions,
+  RouterLinkTyped,
+} from './RouterLink'
 export { RouterView } from './RouterView'
 export type { RouterViewProps } from './RouterView'