From: Eduardo San Martin Morote Date: Wed, 12 Jun 2024 08:34:13 +0000 (+0200) Subject: feat: type useLink X-Git-Tag: v4.4.0-alpha.1~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6a907746db930161902d80e0d254c56e6a273482;p=thirdparty%2Fvuejs%2Frouter.git feat: type useLink --- diff --git a/packages/playground/src/App.vue b/packages/playground/src/App.vue index a3889355..170d7391 100644 --- a/packages/playground/src/App.vue +++ b/packages/playground/src/App.vue @@ -184,7 +184,7 @@ diff --git a/packages/router/src/RouterLink.ts b/packages/router/src/RouterLink.ts index 9531ba65..731dfbf7 100644 --- a/packages/router/src/RouterLink.ts +++ b/packages/router/src/RouterLink.ts @@ -25,6 +25,7 @@ import { RendererNode, // @ts-ignore ComponentOptionsMixin, + MaybeRef, } from 'vue' import { isSameRouteLocationParams, isSameRouteRecord } from './location' import { routerKey, routeLocationKey } from './injectionSymbols' @@ -32,11 +33,15 @@ import { RouteRecord } from './matcher/types' import { NavigationFailure } from './errors' import { isArray, isBrowser, noop } from './utils' import { warn } from './warning' -import { isRouteLocation, type VueUseOptions } from './types' +import { isRouteLocation } from './types' import { RouteLocation, + RouteLocationAsPath, + RouteLocationAsRelativeTyped, + RouteLocationAsString, RouteLocationRaw, RouteLocationResolved, + RouteMap, } from './typed-routes' export interface RouterLinkOptions { @@ -80,6 +85,10 @@ export interface RouterLinkProps extends RouterLinkOptions { | 'false' } +/** + * Context passed from router-link components to devtools. + * @internal + */ export interface UseLinkDevtoolsContext { route: RouteLocationResolved isActive: boolean @@ -87,11 +96,41 @@ export interface UseLinkDevtoolsContext { error: string | null } -export type UseLinkOptions = VueUseOptions +/** + * Options passed to {@link useLink}. + */ +export interface UseLinkOptions { + to: MaybeRef< + | RouteLocationAsString + | RouteLocationAsRelativeTyped + | RouteLocationAsPath + | RouteLocationRaw + > + replace?: MaybeRef +} + +/** + * Return type of {@link useLink}. + * @internal + */ +export interface UseLinkReturn { + route: ComputedRef> + href: ComputedRef + isActive: ComputedRef + isExactActive: ComputedRef + navigate(e?: MouseEvent): Promise +} // TODO: we could allow currentRoute as a prop to expose `isActive` and // `isExactActive` behavior should go through an RFC -export function useLink(props: UseLinkOptions) { +/** + * Returns the internal behavior of a {@link RouterLink} without the rendering part. + * + * @param props - a `to` location and an optional `replace` flag + */ +export function useLink( + props: UseLinkOptions +): UseLinkReturn { const router = inject(routerKey)! const currentRoute = inject(routeLocationKey)! @@ -316,7 +355,8 @@ export interface _RouterLinkI { isActive, isExactActive, navigate, - }: UnwrapRef>) => VNode[] + }: // TODO: How do we add the name generic + UnwrapRef) => VNode[] } } diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts index 058feeba..7e1464b3 100644 --- a/packages/router/src/index.ts +++ b/packages/router/src/index.ts @@ -75,9 +75,9 @@ export type { // route location RouteLocationRaw, RouteLocation, + RouteLocationGeneric, RouteLocationTyped, RouteLocationTypedList, - RouteLocationGeneric, // RouteLocationNormalized RouteLocationNormalizedGeneric, @@ -92,20 +92,23 @@ export type { RouteLocationNormalizedLoadedTypedList, // RouteLocationResolved - RouteLocationResolved, RouteLocationResolvedGeneric, + RouteLocationResolved, RouteLocationResolvedTyped, RouteLocationResolvedTypedList, // relative - RouteLocationAsRelative, RouteLocationAsRelativeGeneric, + RouteLocationAsRelative, RouteLocationAsRelativeTyped, RouteLocationAsRelativeTypedList, // string + RouteLocationAsStringTyped, RouteLocationAsString, + RouteLocationAsStringTypedList, // as path RouteLocationAsPathGeneric, + RouteLocationAsPath, RouteLocationAsPathTyped, RouteLocationAsPathTypedList, diff --git a/packages/router/src/router.ts b/packages/router/src/router.ts index c5a32372..b54e0cec 100644 --- a/packages/router/src/router.ts +++ b/packages/router/src/router.ts @@ -16,6 +16,9 @@ import type { NavigationGuardWithThis, NavigationHookAfter, RouteLocationResolved, + RouteLocationAsRelative, + RouteLocationAsPath, + RouteLocationAsString, } from './typed-routes' import { RouterHistory, HistoryState, NavigationType } from './history/common' import { @@ -64,11 +67,7 @@ import { } from './injectionSymbols' import { addDevtools } from './devtools' import { _LiteralUnion } from './types/utils' -import { - RouteLocationAsPathTyped, - RouteLocationAsRelativeTyped, - RouteLocationAsString, -} from './typed-routes/route-location' +import { RouteLocationAsRelativeTyped } from './typed-routes/route-location' import { RouteMap } from './typed-routes/route-map' /** @@ -249,12 +248,16 @@ export interface Router { * @param currentLocation - Optional current location to resolve against */ resolve( - to: - | RouteLocationAsString - | RouteLocationAsRelativeTyped - | RouteLocationAsPathTyped, + to: RouteLocationAsRelativeTyped, + // NOTE: This version doesn't work probably because it infers the type too early + // | RouteLocationAsRelative currentLocation?: RouteLocationNormalizedLoaded ): RouteLocationResolved + resolve( + // not having the overload produces errors in RouterLink calls to router.resolve() + to: RouteLocationAsString | RouteLocationAsRelative | RouteLocationAsPath, + currentLocation?: RouteLocationNormalizedLoaded + ): RouteLocationResolved /** * Programmatically navigate to a new URL by pushing an entry in the history diff --git a/packages/router/src/typed-routes/route-location.ts b/packages/router/src/typed-routes/route-location.ts index 6cf08cee..2807afcb 100644 --- a/packages/router/src/typed-routes/route-location.ts +++ b/packages/router/src/typed-routes/route-location.ts @@ -34,7 +34,6 @@ export interface RouteLocationGeneric extends _RouteLocationBase { /** * Helper to generate a type safe version of the {@link RouteLocation} type. - * @internal */ export interface RouteLocationTyped< RouteMap extends RouteMapGeneric, @@ -67,7 +66,6 @@ export interface RouteLocationNormalizedGeneric extends _RouteLocationBase { /** * Helper to generate a type safe version of the {@link RouteLocationNormalized} type. - * @internal */ export interface RouteLocationNormalizedTyped< RouteMap extends RouteMapGeneric = RouteMapGeneric, @@ -107,7 +105,6 @@ export interface RouteLocationNormalizedLoadedGeneric /** * Helper to generate a type safe version of the {@link RouteLocationNormalizedLoaded} type. - * @internal */ export interface RouteLocationNormalizedLoadedTyped< RouteMap extends RouteMapGeneric = RouteMapGeneric, @@ -142,7 +139,6 @@ export interface RouteLocationAsRelativeGeneric /** * Helper to generate a type safe version of the {@link RouteLocationAsRelative} type. - * @internal */ export interface RouteLocationAsRelativeTyped< RouteMap extends RouteMapGeneric = RouteMapGeneric, @@ -174,7 +170,6 @@ export interface RouteLocationAsPathGeneric /** * Helper to generate a type safe version of the {@link RouteLocationAsPath} type. - * @internal */ export interface RouteLocationAsPathTyped< RouteMap extends RouteMapGeneric = RouteMapGeneric, @@ -187,13 +182,29 @@ export interface RouteLocationAsPathTyped< } /** - * Type safe version to auto complete the path of a route. + * List of all possible {@link RouteLocationAsPath} indexed by the route name. * @internal */ export type RouteLocationAsPathTypedList< RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationAsPathTyped } +/** + * Helper to generate a type safe version of the {@link RouteLocationAsString} type. + */ +export type RouteLocationAsStringTyped< + RouteMap extends RouteMapGeneric = RouteMapGeneric, + Name extends keyof RouteMap = keyof RouteMap +> = RouteMap[Name]['path'] + +/** + * List of all possible {@link RouteLocationAsString} indexed by the route name. + * @internal + */ +export type RouteLocationAsStringTypedList< + RouteMap extends RouteMapGeneric = RouteMapGeneric +> = { [N in keyof RouteMap]: RouteLocationAsStringTyped } + /** * Generic version of {@link RouteLocationResolved}. It is used when no {@link RouteMap} is provided. */ @@ -206,7 +217,6 @@ export interface RouteLocationResolvedGeneric extends RouteLocationGeneric { /** * Helper to generate a type safe version of the {@link RouteLocationResolved} type. - * @internal */ export interface RouteLocationResolvedTyped< RouteMap extends RouteMapGeneric, @@ -278,14 +288,21 @@ export type RouteLocationResolved< : RouteLocationResolvedTypedList[Name] /** - * Same as {@link RouteLocationAsPathTyped} but as a string literal. - * @internal + * Same as {@link RouteLocationAsPath} but as a string literal. */ export type RouteLocationAsString< - RouteMap extends RouteMapGeneric = RouteMapGeneric + Name extends keyof RouteMap = keyof RouteMap > = RouteMapGeneric extends RouteMap ? string - : _LiteralUnion + : _LiteralUnion[Name], string> + +/** + * Route location as an object with a `path` property. + */ +export type RouteLocationAsPath = + RouteMapGeneric extends RouteMap + ? RouteLocationAsPathGeneric + : RouteLocationAsPathTypedList[Name] /** * Route location that can be passed to `router.push()` and other user-facing APIs. @@ -293,10 +310,10 @@ export type RouteLocationAsString< export type RouteLocationRaw = RouteMapGeneric extends RouteMap ? - | RouteLocationAsString + | RouteLocationAsStringTyped | RouteLocationAsRelativeGeneric | RouteLocationAsPathGeneric : - | RouteLocationAsString + | RouteLocationAsStringTyped | RouteLocationAsRelativeTypedList[Name] | RouteLocationAsPathTypedList[Name]