Skip to content

Commit

Permalink
feat(types): typed useLink()
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Jul 7, 2022
1 parent d6b5460 commit 55bf04e
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 9 deletions.
12 changes: 11 additions & 1 deletion playground/src/App.vue
@@ -1,11 +1,21 @@
<script setup lang="ts">
import { useRoute } from '@vue-router'
import { useLink, useRoute } from '@vue-router'
import type { RouteNamedMap } from '@vue-router/routes'
const route = useRoute()
if (route.name === '/deep/nesting/works/[[files]]+') {
route.params.files
}
const router = useRouter()
router.resolve('/:name')
router.resolve({ name: '/[name]' }).params.name
useLink('/:path(.*)')
useLink({ path: '/articles/:id' })
useLink({ name: '/[name]', params: { name: 'hey' } }).route.value.params.name
const customRoute = useRoute('/deep/nesting/works/custom-path')
</script>

Expand Down
3 changes: 3 additions & 0 deletions playground/typed-router.d.ts
Expand Up @@ -15,6 +15,7 @@ import type {
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
UseLinkFnTyped,
} from 'unplugin-vue-router'

declare module '@vue-router/routes' {
Expand Down Expand Up @@ -68,6 +69,8 @@ declare module '@vue-router' {
export function useRouter(): RouterTyped
export function useRoute<Name extends keyof RouteNamedMap = keyof RouteNamedMap>(name?: Name): RouteLocationNormalizedLoadedTypedList<RouteNamedMap>[Name]

export const useLink: UseLinkFnTyped<RouteNamedMap>

export function onBeforeRouteLeave(guard: NavigationGuard<RouteNamedMap>): void
export function onBeforeRouteUpdate(guard: NavigationGuard<RouteNamedMap>): void
}
Expand Down
3 changes: 3 additions & 0 deletions src/core/context.ts
Expand Up @@ -146,6 +146,7 @@ import type {
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
UseLinkFnTyped,
} from 'unplugin-vue-router'
declare module '${MODULE_ROUTES_PATH}' {
Expand Down Expand Up @@ -176,6 +177,8 @@ declare module '${MODULE_VUE_ROUTER}' {
export function useRouter(): RouterTyped
export function useRoute<Name extends keyof RouteNamedMap = keyof RouteNamedMap>(name?: Name): RouteLocationNormalizedLoadedTypedList<RouteNamedMap>[Name]
export const useLink: UseLinkFnTyped<RouteNamedMap>
export function onBeforeRouteLeave(guard: NavigationGuard<RouteNamedMap>): void
export function onBeforeRouteUpdate(guard: NavigationGuard<RouteNamedMap>): void
}
Expand Down
6 changes: 5 additions & 1 deletion src/index.ts
Expand Up @@ -95,7 +95,11 @@ export type {
} from './typeExtensions/routeLocation'
export type { NavigationGuard } from './typeExtensions/navigationGuards'
export type { _RouterTyped } from './typeExtensions/router'
export type { RouterLinkTyped } from './typeExtensions/RouterLink'
export type {
RouterLinkTyped,
UseLinkFnTyped,
_UseLinkReturnTyped,
} from './typeExtensions/RouterLink'
export type {
ParamValue,
ParamValueOneOrMore,
Expand Down
56 changes: 49 additions & 7 deletions src/typeExtensions/RouterLink.ts
Expand Up @@ -3,26 +3,42 @@ import type {
ComponentCustomProps,
VNodeProps,
VNode,
ComputedRef,
} from 'vue'
import type { RouterLinkProps as _RouterLinkProps } from 'vue-router'
import type {
NavigationFailure,
RouterLinkProps as _RouterLinkProps,
} from 'vue-router'
import type { _RouterTyped } from './router'

// TODO: could this have a name generic to type the slot? is it
// TODO: could this have a name generic to type the slot? is it possible

import { _RouteMapGeneric } from '../codegen/generateRouteMap'
import {
RouteLocationAsPathTyped,
RouteLocationAsPathTypedList,
RouteLocationAsRelativeTyped,
RouteLocationAsRelativeTypedList,
RouteLocationAsString,
RouteLocationResolvedTypedList,
} from './routeLocation'

export interface RouterLinkProps<RouteMap extends _RouteMapGeneric>
extends Omit<_RouterLinkProps, 'to'> {
/**
* Typed version of `RouterLinkProps`.
*/
export interface RouterLinkProps<
RouteMap extends _RouteMapGeneric,
Name extends keyof RouteMap = keyof RouteMap
> extends Omit<_RouterLinkProps, 'to'> {
to:
| RouteLocationAsString<RouteMap>
| RouteLocationAsRelativeTypedList<RouteMap>[keyof RouteMap]
| RouteLocationAsPathTypedList<RouteMap>[keyof RouteMap]
| RouteLocationAsRelativeTypedList<RouteMap>[Name]
| RouteLocationAsPathTypedList<RouteMap>[Name]
}

/**
* Typed version of `<RouterLink>` component.
*/
export interface RouterLinkTyped<RouteMap extends _RouteMapGeneric> {
new (): {
$props: AllowedComponentProps &
Expand All @@ -37,4 +53,30 @@ export interface RouterLinkTyped<RouteMap extends _RouteMapGeneric> {
}
}

// TODO: typed useLink()
// TODO: should be exposed by the router instead
/**
* Return type of `useLink()`. Should be exposed by the router instead.
* @internal
*/
export interface _UseLinkReturnTyped<
RouteMap extends _RouteMapGeneric,
Name extends keyof RouteMap = keyof RouteMap
> {
route: ComputedRef<RouteLocationResolvedTypedList<RouteMap>[Name]>
href: ComputedRef<string>
isActive: ComputedRef<boolean>
isExactActive: ComputedRef<boolean>
navigate(e?: MouseEvent): Promise<void | NavigationFailure>
}

/**
* Typed version of `useLink()`.
*/
export interface UseLinkFnTyped<RouteMap extends _RouteMapGeneric> {
<Name extends keyof RouteMap = keyof RouteMap>(
to:
| RouteLocationAsString<RouteMap>
| RouteLocationAsRelativeTyped<RouteMap, Name>
| RouteLocationAsPathTyped<RouteMap, Name>
): _UseLinkReturnTyped<RouteMap, Name>
}

0 comments on commit 55bf04e

Please sign in to comment.