From: Eduardo San Martin Morote Date: Tue, 11 Jun 2024 09:19:02 +0000 (+0200) Subject: refactor: remove old types X-Git-Tag: v4.4.0-alpha.0~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4e0d730509338f1de797b2ccc5afa8abe5284f16;p=thirdparty%2Fvuejs%2Frouter.git refactor: remove old types --- diff --git a/packages/router/__tests__/RouterLink.spec.ts b/packages/router/__tests__/RouterLink.spec.ts index 76b335b1..608c2e88 100644 --- a/packages/router/__tests__/RouterLink.spec.ts +++ b/packages/router/__tests__/RouterLink.spec.ts @@ -2,13 +2,14 @@ * @jest-environment jsdom */ import { RouterLink } from '../src/RouterLink' +import { RouteQueryAndHash, MatcherLocationRaw } from '../src/types' +import { START_LOCATION_NORMALIZED } from '../src/location' import { - RouteQueryAndHash, - MatcherLocationRaw, + createMemoryHistory, + RouterOptions, RouteLocationNormalized, -} from '../src/types' -import { START_LOCATION_NORMALIZED } from '../src/location' -import { createMemoryHistory, RouterOptions } from '../src' + RouteLocationResolved, +} from '../src' import { createMockedRoute } from './mount' import { defineComponent, PropType } from 'vue' import { RouteRecordNormalized } from '../src/matcher/types' @@ -37,8 +38,6 @@ records.parentAlias = { records.childAlias = { aliasOf: records.child } as RouteRecordNormalized records.childEmptyAlias.aliasOf = records.childEmpty -type RouteLocationResolved = RouteLocationNormalized & { href: string } - function createLocations< T extends Record< string, diff --git a/packages/router/__tests__/RouterView.spec.ts b/packages/router/__tests__/RouterView.spec.ts index 8f1a4d1b..c41084c1 100644 --- a/packages/router/__tests__/RouterView.spec.ts +++ b/packages/router/__tests__/RouterView.spec.ts @@ -3,12 +3,12 @@ */ import { RouterView } from '../src/RouterView' import { components, RouteLocationNormalizedLoose } from './utils' -import { RouteLocationNormalized } from '../src/types' import { START_LOCATION_NORMALIZED } from '../src/location' import { markRaw } from 'vue' import { createMockedRoute } from './mount' import { mockWarn } from 'jest-mock-warn' import { mount } from '@vue/test-utils' +import { RouteLocationNormalized } from '../src' // to have autocompletion function createRoutes>( diff --git a/packages/router/__tests__/guards/beforeEach.spec.ts b/packages/router/__tests__/guards/beforeEach.spec.ts index ddc15ef0..579eb1f9 100644 --- a/packages/router/__tests__/guards/beforeEach.spec.ts +++ b/packages/router/__tests__/guards/beforeEach.spec.ts @@ -1,6 +1,7 @@ import fakePromise from 'faked-promise' import { createDom, tick, noGuard, newRouter as createRouter } from '../utils' -import { RouteRecordRaw, RouteLocationRaw } from '../../src/types' +import { RouteRecordRaw } from '../../src/types' +import { RouteLocationRaw } from '../../src' const Home = { template: `
Home
` } const Foo = { template: `
Foo
` } diff --git a/packages/router/__tests__/guards/loadRouteLocation.spec.ts b/packages/router/__tests__/guards/loadRouteLocation.spec.ts index e1c63d13..6e6b5e7d 100644 --- a/packages/router/__tests__/guards/loadRouteLocation.spec.ts +++ b/packages/router/__tests__/guards/loadRouteLocation.spec.ts @@ -1,7 +1,7 @@ import { isRouteComponent, loadRouteLocation } from '../../src/navigationGuards' -import { RouteRecordRaw, RouteLocationRaw } from '../../src/types' +import { RouteRecordRaw } from '../../src/types' import { components } from '../utils' -import { createMemoryHistory, createRouter } from '../../src' +import { RouteLocationRaw, createMemoryHistory, createRouter } from '../../src' import { FunctionalComponent } from 'vue' const FunctionalHome: FunctionalComponent = () => null diff --git a/packages/router/__tests__/router.spec.ts b/packages/router/__tests__/router.spec.ts index 9f61c7aa..0d143fa7 100644 --- a/packages/router/__tests__/router.spec.ts +++ b/packages/router/__tests__/router.spec.ts @@ -4,10 +4,12 @@ import { createMemoryHistory, createWebHistory, createWebHashHistory, + loadRouteLocation, + RouteLocationRaw, } from '../src' import { NavigationFailureType } from '../src/errors' import { createDom, components, tick, nextNavigation } from './utils' -import { RouteRecordRaw, RouteLocationRaw } from '../src/types' +import { RouteRecordRaw } from '../src/types' import { mockWarn } from 'jest-mock-warn' import { START_LOCATION_NORMALIZED } from '../src/location' @@ -465,7 +467,9 @@ describe('Router', () => { expect( router.resolve( { params: { p: 1 } }, - router.resolve({ name: 'Param', params: { p: 2 } }) + await loadRouteLocation( + router.resolve({ name: 'Param', params: { p: 2 } }) + ) ) ).toMatchObject({ name: 'Param', diff --git a/packages/router/__tests__/utils.ts b/packages/router/__tests__/utils.ts index 1d4e8132..a6020fc3 100644 --- a/packages/router/__tests__/utils.ts +++ b/packages/router/__tests__/utils.ts @@ -4,7 +4,6 @@ import { MatcherLocation, RouteComponent, RouteRecordRaw, - _RouteRecordProps, } from '../src/types' import { h, ComponentOptions } from 'vue' import { @@ -17,6 +16,7 @@ import { NavigationGuard, RouteLocationNormalized, } from '../src' +import { _RouteRecordProps } from '../src/typed-routes' export const tick = (time?: number) => new Promise(resolve => { diff --git a/packages/router/src/RouterLink.ts b/packages/router/src/RouterLink.ts index 6db1f235..9531ba65 100644 --- a/packages/router/src/RouterLink.ts +++ b/packages/router/src/RouterLink.ts @@ -26,17 +26,17 @@ import { // @ts-ignore ComponentOptionsMixin, } from 'vue' -import { isRouteLocation, type VueUseOptions } 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 { warn } from './warning' +import { isRouteLocation, type VueUseOptions } from './types' import { RouteLocation, - RouteLocationNormalized, RouteLocationRaw, + RouteLocationResolved, } from './typed-routes' export interface RouterLinkOptions { @@ -81,8 +81,7 @@ export interface RouterLinkProps extends RouterLinkOptions { } export interface UseLinkDevtoolsContext { - // TODO: loaded type ? - route: RouteLocationNormalized & { href: string } + route: RouteLocationResolved isActive: boolean isExactActive: boolean error: string | null @@ -127,10 +126,7 @@ export function useLink(props: UseLinkOptions) { hasPrevious = true } - return router.resolve( - // @ts-expect-error: FIXME: errors on the name because of typed routes - to - ) + return router.resolve(to) }) const activeRecordIndex = computed(() => { diff --git a/packages/router/src/devtools.ts b/packages/router/src/devtools.ts index b543fa80..e4bef80d 100644 --- a/packages/router/src/devtools.ts +++ b/packages/router/src/devtools.ts @@ -16,8 +16,8 @@ import { PathParser } from './matcher/pathParserRanker' import { Router } from './router' import { UseLinkDevtoolsContext } from './RouterLink' import { RouterViewDevtoolsContext } from './RouterView' -import { RouteLocationNormalized } from './types' import { assign, isArray } from './utils' +import { RouteLocationNormalized } from './typed-routes' /** * Copies a route location and removes any problematic properties that cannot be shown in devtools (e.g. Vue instances). diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts index d93edc49..ae19d6ef 100644 --- a/packages/router/src/index.ts +++ b/packages/router/src/index.ts @@ -61,7 +61,6 @@ export type { RouteMeta, RouteComponent, // RawRouteComponent, - NavigationGuardNext, } from './types' // Experimental Type Safe API @@ -72,7 +71,7 @@ export type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteLocationResolved, - RouteLocationAsRelativePath, + RouteLocationAsRelative, // route records RouteRecordInfo, @@ -92,6 +91,7 @@ export type { NavigationGuardWithThis, NavigationHookAfter, NavigationGuardReturn, + NavigationGuardNext, } from './typed-routes' export { createRouter } from './router' diff --git a/packages/router/src/location.ts b/packages/router/src/location.ts index 98693970..5d5386eb 100644 --- a/packages/router/src/location.ts +++ b/packages/router/src/location.ts @@ -1,5 +1,5 @@ import { LocationQuery, LocationQueryRaw } from './query' -import { RouteLocationNormalized, RouteParamValue } from './types' +import { RouteParamValue, RouteParamsGeneric } from './types' import { RouteRecord } from './matcher/types' import { warn } from './warning' import { isArray } from './utils' @@ -156,8 +156,8 @@ export function isSameRouteRecord(a: RouteRecord, b: RouteRecord): boolean { } export function isSameRouteLocationParams( - a: RouteLocationNormalized['params'], - b: RouteLocationNormalized['params'] + a: RouteParamsGeneric, + b: RouteParamsGeneric ): boolean { if (Object.keys(a).length !== Object.keys(b).length) return false @@ -262,7 +262,6 @@ export function resolveRelativePath(to: string, from: string): string { */ export const START_LOCATION_NORMALIZED: RouteLocationNormalizedLoaded = { path: '/', - // @ts-expect-error: internal name for compatibility name: undefined, // TODO: could we use a symbol in the future? params: {}, diff --git a/packages/router/src/matcher/index.ts b/packages/router/src/matcher/index.ts index b40a0b89..c4ad8f55 100644 --- a/packages/router/src/matcher/index.ts +++ b/packages/router/src/matcher/index.ts @@ -3,7 +3,6 @@ import { MatcherLocationRaw, MatcherLocation, isRouteName, - _RouteRecordProps, } from '../types' import { createRouterError, ErrorTypes, MatcherError } from '../errors' import { createRouteRecordMatcher, RouteRecordMatcher } from './pathMatcher' @@ -19,7 +18,7 @@ import { comparePathParserScore } from './pathParserRanker' import { warn } from '../warning' import { assign, noop } from '../utils' -import type { RouteRecordName } from '../typed-routes' +import type { RouteRecordName, _RouteRecordProps } from '../typed-routes' /** * Internal RouterMatcher @@ -30,10 +29,12 @@ export interface RouterMatcher { addRoute: (record: RouteRecordRaw, parent?: RouteRecordMatcher) => () => void removeRoute(matcher: RouteRecordMatcher): void - removeRoute(name: RouteRecordName): void + removeRoute(name: NonNullable): void getRoutes: () => RouteRecordMatcher[] - getRecordMatcher: (name: RouteRecordName) => RouteRecordMatcher | undefined + getRecordMatcher: ( + name: NonNullable + ) => RouteRecordMatcher | undefined /** * Resolves a location. Gives access to the route record that corresponds to the actual path as well as filling the corresponding params objects @@ -193,7 +194,9 @@ export function createRouterMatcher( : noop } - function removeRoute(matcherRef: RouteRecordName | RouteRecordMatcher) { + function removeRoute( + matcherRef: NonNullable | RouteRecordMatcher + ) { if (isRouteName(matcherRef)) { const matcher = matcherMap.get(matcherRef) if (matcher) { diff --git a/packages/router/src/matcher/types.ts b/packages/router/src/matcher/types.ts index 774c79d4..5efab055 100644 --- a/packages/router/src/matcher/types.ts +++ b/packages/router/src/matcher/types.ts @@ -1,9 +1,11 @@ -import type { NavigationGuard } from '../typed-routes' +import type { + NavigationGuard, + NavigationGuardNextCallback, + _RouteRecordProps, +} from '../typed-routes' import { RouteRecordMultipleViews, _RouteRecordBase, - _RouteRecordProps, - NavigationGuardNextCallback, RouteRecordRaw, } from '../types' import { ComponentPublicInstance } from 'vue' diff --git a/packages/router/src/navigationGuards.ts b/packages/router/src/navigationGuards.ts index 2c981e1b..b1b9268a 100644 --- a/packages/router/src/navigationGuards.ts +++ b/packages/router/src/navigationGuards.ts @@ -1,19 +1,18 @@ import { - NavigationGuardNext, - NavigationGuardNextCallback, isRouteLocation, Lazy, RouteComponent, RawRouteComponent, - - // NOTE: Still need to use some old types while migrating - RouteLocationRaw as RouteLocationRaw_OLD, } from './types' import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, NavigationGuard, + RouteLocation, + RouteLocationRaw, + NavigationGuardNext, + NavigationGuardNextCallback, } from './typed-routes' import { @@ -142,12 +141,7 @@ export function guardToPromiseFn( return () => new Promise((resolve, reject) => { const next: NavigationGuardNext = ( - valid?: - | boolean - // TODO: remove - | RouteLocationRaw_OLD - | NavigationGuardNextCallback - | Error + valid?: boolean | RouteLocationRaw | NavigationGuardNextCallback | Error ) => { if (valid === false) { reject( @@ -378,7 +372,7 @@ export function isRouteComponent( * @param route - resolved route to load */ export function loadRouteLocation( - route: RouteLocationNormalized + route: RouteLocation | RouteLocationNormalized ): Promise { return route.matched.every(record => record.redirect) ? Promise.reject(new Error('Cannot load a route that redirects.')) diff --git a/packages/router/src/router.ts b/packages/router/src/router.ts index 3be4a7ff..f05de580 100644 --- a/packages/router/src/router.ts +++ b/packages/router/src/router.ts @@ -212,7 +212,10 @@ export interface Router { * @param parentName - Parent Route Record where `route` should be appended at * @param route - Route Record to add */ - addRoute(parentName: RouteRecordName, route: RouteRecordRaw): () => void + addRoute( + parentName: NonNullable, + route: RouteRecordRaw + ): () => void /** * Add a new {@link RouteRecordRaw | route record} to the router. * @@ -230,7 +233,7 @@ export interface Router { * * @param name - Name of the route to check */ - hasRoute(name: RouteRecordName): boolean + hasRoute(name: NonNullable): boolean /** * Get a full list of all the {@link RouteRecord | route records}. */ @@ -404,7 +407,7 @@ export function createRouter(options: RouterOptions): Router { applyToParams.bind(null, decode) function addRoute( - parentOrRoute: RouteRecordName | RouteRecordRaw, + parentOrRoute: NonNullable | RouteRecordRaw, route?: RouteRecordRaw ) { let parent: Parameters<(typeof matcher)['addRoute']>[1] | undefined @@ -427,7 +430,7 @@ export function createRouter(options: RouterOptions): Router { return matcher.addRoute(record, parent) } - function removeRoute(name: RouteRecordName) { + function removeRoute(name: NonNullable) { const recordMatcher = matcher.getRecordMatcher(name) if (recordMatcher) { matcher.removeRoute(recordMatcher) @@ -440,7 +443,7 @@ export function createRouter(options: RouterOptions): Router { return matcher.getRoutes().map(routeMatcher => routeMatcher.record) } - function hasRoute(name: RouteRecordName): boolean { + function hasRoute(name: NonNullable): boolean { return !!matcher.getRecordMatcher(name) } @@ -1225,7 +1228,6 @@ export function createRouter(options: RouterOptions): Router { removeRoute, hasRoute, getRoutes, - // @ts-expect-error: FIXME: types do not match resolve, options, diff --git a/packages/router/src/scrollBehavior.ts b/packages/router/src/scrollBehavior.ts index 7072604a..64255645 100644 --- a/packages/router/src/scrollBehavior.ts +++ b/packages/router/src/scrollBehavior.ts @@ -1,4 +1,7 @@ -import { RouteLocationNormalized, RouteLocationNormalizedLoaded } from './types' +import type { + RouteLocationNormalized, + RouteLocationNormalizedLoaded, +} from './typed-routes' import { warn } from './warning' // we use types instead of interfaces to make it work with HistoryStateValue type diff --git a/packages/router/src/typed-routes/index.ts b/packages/router/src/typed-routes/index.ts index deff65da..b91914c1 100644 --- a/packages/router/src/typed-routes/index.ts +++ b/packages/router/src/typed-routes/index.ts @@ -3,27 +3,34 @@ export type { ParamValueOneOrMore, ParamValueZeroOrMore, ParamValueZeroOrOne, + RouteParams, + RouteParamsRaw, } from './params' export type { RouteRecordInfo } from './route-map' export type { - RouteRecordName as RouteRecordName, - _RouteLocationRaw as RouteLocationRaw, + RouteRecordName, + RouteLocationRaw, RouteLocation, - _RouteLocationNormalized as RouteLocationNormalized, - _RouteLocationNormalizedLoaded as RouteLocationNormalizedLoaded, - _RouteLocationResolved as RouteLocationResolved, - _RouteLocationAsRelativePath as RouteLocationAsRelativePath, - _RouteParams as RouteParams, - _RouteParamsRaw as RouteParamsRaw, + RouteLocationNormalized, + RouteLocationNormalizedGeneric, + RouteLocationNormalizedLoaded, + RouteLocationResolved, + RouteLocationAsRelative, } from './route-location' -export type { RouteRecordRedirectOption } from './route-records' +export type { + RouteRecordRedirectOption, + RouteRecordNameGeneric, + _RouteRecordProps, +} from './route-records' export type { NavigationGuard, NavigationGuardReturn, NavigationHookAfter, NavigationGuardWithThis, + NavigationGuardNext, + NavigationGuardNextCallback, } from './navigation-guards' diff --git a/packages/router/src/typed-routes/navigation-guards.ts b/packages/router/src/typed-routes/navigation-guards.ts index b4dac11b..ab624e1f 100644 --- a/packages/router/src/typed-routes/navigation-guards.ts +++ b/packages/router/src/typed-routes/navigation-guards.ts @@ -1,60 +1,34 @@ import type { _Awaitable } from '../types/utils' -import type { NavigationGuardNext } from '../types' import type { - _RouteLocationNormalizedLoaded, - RouteLocationNormalizedTypedList, - RouteLocationNormalizedLoadedTypedList, - RouteLocationAsString, - RouteLocationAsRelativeTypedList, - RouteLocationAsPathTypedList, - _RouteLocationNormalized, + RouteLocationNormalizedLoaded, + RouteLocationNormalized, + RouteLocationRaw, } from './route-location' -import type { _RouteMapGeneric, RouteMap } from './route-map' +import type { TypesConfig } from '../config' import type { NavigationFailure } from '../errors' - -/** - * Return types for a Navigation Guard. Accepts a type param for the RouteMap. - */ -type NavigationGuardReturnTyped = - | void - | Error - | boolean - | RouteLocationAsString - | RouteLocationAsRelativeTypedList[keyof RouteMap] - | RouteLocationAsPathTypedList[keyof RouteMap] +import { ComponentPublicInstance } from 'vue' /** * Return types for a Navigation Guard. Based on `TypesConfig` * * @see {@link TypesConfig} - * @see {@link NavigationGuardReturnTyped} */ -export type NavigationGuardReturn = NavigationGuardReturnTyped +export type NavigationGuardReturn = void | Error | boolean | RouteLocationRaw /** - * Typed Navigation Guard with a type parameter for `this` and another for the route map. + * Navigation Guard with a type parameter for `this`. + * @see {@link TypesConfig} */ -export interface NavigationGuardWithThisTyped< - T, - RouteMap extends _RouteMapGeneric -> { +export interface NavigationGuardWithThis { ( this: T, - to: RouteLocationNormalizedTypedList[keyof RouteMap], - from: RouteLocationNormalizedLoadedTypedList[keyof RouteMap], + to: RouteLocationNormalized, + from: RouteLocationNormalizedLoaded, // intentionally not typed to make people use the return next: NavigationGuardNext - ): _Awaitable> + ): _Awaitable } -/** - * Typed Navigation Guard with a type parameter for `this`. Based on `TypesConfig` - * @see {@link TypesConfig} - * @see {@link NavigationGuardWithThisTyped} - */ -export interface NavigationGuardWithThis - extends NavigationGuardWithThisTyped {} - /** * In `router.beforeResolve((to) => {})`, the `to` is typed as `RouteLocationNormalizedLoaded`, not * `RouteLocationNormalized` like in `router.beforeEach()`. In practice it doesn't change much as users do not rely on @@ -64,47 +38,57 @@ export interface NavigationGuardWithThis export interface _NavigationGuardResolved { ( this: undefined, - to: _RouteLocationNormalizedLoaded, - from: _RouteLocationNormalizedLoaded, + to: RouteLocationNormalizedLoaded, + from: RouteLocationNormalizedLoaded, // intentionally not typed to make people use the return next: NavigationGuardNext ): _Awaitable } /** - * Typed Navigation Guard. Accepts a type param for the RouteMap. + * Navigation Guard. */ -export interface NavigationGuardTyped { +export interface NavigationGuard { ( - to: _RouteLocationNormalized, - from: _RouteLocationNormalizedLoaded, + to: RouteLocationNormalized, + from: RouteLocationNormalizedLoaded, // intentionally not typed to make people use the return next: NavigationGuardNext - ): _Awaitable> + ): _Awaitable } /** - * Typed Navigation Guard. Based on `TypesConfig`. - * @see {@link TypesConfig} - * @see {@link NavigationGuardWithThisTyped} + * Navigation hook triggered after a navigation is settled. */ -export type NavigationGuard = NavigationGuardTyped - -/** - * Typed Navigation Hook After. Accepts a type param for the RouteMap. - */ -export interface NavigationHookAfterTyped { +export interface NavigationHookAfter { ( - to: RouteLocationNormalizedTypedList[keyof RouteMap], - from: RouteLocationNormalizedLoadedTypedList[keyof RouteMap], + to: RouteLocationNormalized, + from: RouteLocationNormalizedLoaded, failure?: NavigationFailure | void ): unknown } /** - * Typed Navigation Hook After. Based on `TypesConfig`. - * @see {@link TypesConfig} - * @see {@link NavigationHookAfterTyped} + * `next()` callback passed to navigation guards. + */ +export interface NavigationGuardNext { + (): void + (error: Error): void + (location: RouteLocationRaw): void + (valid: boolean | undefined): void + (cb: NavigationGuardNextCallback): void + /** + * Allows to detect if `next` isn't called in a resolved guard. Used + * internally in DEV mode to emit a warning. Commented out to simplify + * typings. + * @internal + */ + // _called: boolean +} + +/** + * Callback that can be passed to `next()` in `beforeRouteEnter()` guards. */ -export interface NavigationHookAfter - extends NavigationHookAfterTyped {} +export type NavigationGuardNextCallback = ( + vm: ComponentPublicInstance +) => unknown diff --git a/packages/router/src/typed-routes/params.ts b/packages/router/src/typed-routes/params.ts index 4192ed45..63dc8e9b 100644 --- a/packages/router/src/typed-routes/params.ts +++ b/packages/router/src/typed-routes/params.ts @@ -1,3 +1,5 @@ +import type { RouteMap } from './route-map' + /** * Utility type for raw and non raw params like :id+ * @@ -35,3 +37,17 @@ export type ParamValue = true extends isRaw // export type ParamValueOneOrMoreRaw = [ParamValueRaw, ...ParamValueRaw[]] // export type ParamValue = string // export type ParamValueRaw = string | number + +/** + * Generate a type safe params for a route location. Requires the name of the route to be passed as a generic. + * @see {@link RouteParamsGeneric} + */ +export type RouteParams = + RouteMap[Name]['params'] + +/** + * Generate a type safe raw params for a route location. Requires the name of the route to be passed as a generic. + * @see {@link RouteParamsRaw} + */ +export type RouteParamsRaw = + RouteMap[Name]['paramsRaw'] diff --git a/packages/router/src/typed-routes/route-location.ts b/packages/router/src/typed-routes/route-location.ts index 5f52ff9e..5ebfeedd 100644 --- a/packages/router/src/typed-routes/route-location.ts +++ b/packages/router/src/typed-routes/route-location.ts @@ -1,124 +1,185 @@ import type { - RouteLocationNormalized, - RouteLocationNormalizedLoaded, RouteLocationOptions, RouteQueryAndHash, - RouteLocationRaw, _RouteLocationBase, + RouteParamsGeneric, + RouteLocationMatched, + RouteParamsRawGeneric, } from '../types' import type { _LiteralUnion } from '../types/utils' // inlining the type as it avoids code splitting issues -import type { RouteMap, _RouteMapGeneric } from './route-map' +import type { RouteMap, RouteMapGeneric } from './route-map' import type { Router } from '../router' -import type { RouteRecord } from '../matcher/types' +import type { RouteRecord, RouteRecordNormalized } from '../matcher/types' +import { RouteRecordNameGeneric } from './route-records' /** - * Possible values for a user-defined route record's name + * Possible values for a user-defined route record's name. */ -export type RouteRecordName = keyof RouteMap +export type RouteRecordName = RouteMapGeneric extends RouteMap + ? RouteRecordNameGeneric + : keyof RouteMap /** - * Type safe version of the {@link RouteLocation} type. + * Generic version of {@link RouteLocation}. It is used when no {@link RouteMap} is provided. + */ +export interface RouteLocationGeneric extends _RouteLocationBase { + /** + * Array of {@link RouteRecord} containing components as they were + * passed when adding records. It can also contain redirect records. This + * can't be used directly. **This property is non-enumerable**. + */ + matched: RouteRecord[] +} + +/** + * Helper to generate a type safe version of the {@link RouteLocation} type. * @internal */ export interface RouteLocationTyped< - RouteMap extends _RouteMapGeneric, + RouteMap extends RouteMapGeneric, Name extends keyof RouteMap -> extends _RouteLocationBase { +> extends RouteLocationGeneric { + // Extract is needed because keyof can produce numbers name: Extract params: RouteMap[Name]['params'] - - /** - * Array of {@link RouteRecord} containing components as they were - * passed when adding records. It can also contain redirect records. This - * can't be used directly - */ - matched: RouteRecord[] // non-enumerable } /** - * Type safe version of the {@link RouteLocation} type as a Record with all the routes. + * List of all possible {@link RouteLocation} indexed by the route name. * @internal */ export type RouteLocationTypedList< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric + RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationTyped } /** - * Helper to generate a type safe version of the `RouteLocationNormalized` type. + * Generic version of {@link RouteLocationNormalized} that is used when no {@link RouteMap} is provided. + */ +export interface RouteLocationNormalizedGeneric extends _RouteLocationBase { + name: RouteRecordNameGeneric + params: RouteParamsGeneric + /** + * Array of {@link RouteRecordNormalized} + */ + matched: RouteRecordNormalized[] +} + +/** + * Helper to generate a type safe version of the {@link RouteLocationNormalized} type. * @internal */ export interface RouteLocationNormalizedTyped< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric, + RouteMap extends RouteMapGeneric = RouteMapGeneric, Name extends keyof RouteMap = keyof RouteMap -> extends RouteLocationNormalized { +> extends RouteLocationNormalizedGeneric { name: Extract // we don't override path because it could contain params and in practice it's just not useful params: RouteMap[Name]['params'] + + /** + * Array of {@link RouteRecordNormalized} + */ + matched: RouteRecordNormalized[] // non-enumerable } /** - * Helper to generate a type safe version of the `RouteLocationNormalizedLoaded` type. + * List of all possible {@link RouteLocationNormalized} indexed by the route name. * @internal */ export type RouteLocationNormalizedTypedList< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric + RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationNormalizedTyped } /** - * Helper to generate a type safe version of the `RouteLocationNormalizedLoaded` type. + * Generic version of {@link RouteLocationNormalizedLoaded} that is used when no {@link RouteMap} is provided. + */ +export interface RouteLocationNormalizedLoadedGeneric + extends RouteLocationNormalizedGeneric { + /** + * Array of {@link RouteLocationMatched} containing only plain components (any + * lazy-loaded components have been loaded and were replaced inside the + * `components` object) so it can be directly used to display routes. It + * cannot contain redirect records either. **This property is non-enumerable**. + */ + matched: RouteLocationMatched[] +} + +/** + * Helper to generate a type safe version of the {@link RouteLocationNormalizedLoaded} type. * @internal */ export interface RouteLocationNormalizedLoadedTyped< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric, + RouteMap extends RouteMapGeneric = RouteMapGeneric, Name extends keyof RouteMap = keyof RouteMap -> extends RouteLocationNormalizedLoaded { +> extends RouteLocationNormalizedLoadedGeneric { name: Extract // we don't override path because it could contain params and in practice it's just not useful params: RouteMap[Name]['params'] } /** - * Helper to generate a type safe version of the {@link RouteLocationNormalizedLoaded } type. + * List of all possible {@link RouteLocationNormalizedLoaded} indexed by the route name. * @internal */ export type RouteLocationNormalizedLoadedTypedList< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric + RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationNormalizedLoadedTyped } /** - * Type safe adaptation of {@link LocationAsRelativeRaw}. Used to generate the union of all possible location. + * Generic version of {@link RouteLocationAsRelative}. It is used when no {@link RouteMap} is provided. + */ +export interface RouteLocationAsRelativeGeneric + extends RouteQueryAndHash, + RouteLocationOptions { + name?: RouteRecordName + params?: RouteParamsRawGeneric + /** + * A relative path to the current location. This property should be removed + */ + path?: undefined +} + +/** + * Helper to generate a type safe version of the {@link RouteLocationAsRelative} type. * @internal */ export interface RouteLocationAsRelativeTyped< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric, + RouteMap extends RouteMapGeneric = RouteMapGeneric, Name extends keyof RouteMap = keyof RouteMap -> extends RouteQueryAndHash, - RouteLocationOptions { - name?: Name +> extends RouteLocationAsRelativeGeneric { + name?: Extract params?: RouteMap[Name]['paramsRaw'] - - // A relative path shouldn't have a path. This is easier to check with TS - path?: undefined } /** - * Type safe adaptation of {@link LocationAsRelativeRaw}. Used to generate the union of all possible location. + * List of all possible {@link RouteLocationAsRelative} indexed by the route name. * @internal */ export type RouteLocationAsRelativeTypedList< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric + RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationAsRelativeTyped } /** - * Type safe version to auto complete the path of a route. + * Generic version of {@link RouteLocationAsPath}. It is used when no {@link RouteMap} is provided. + */ +export interface RouteLocationAsPathGeneric + extends RouteQueryAndHash, + RouteLocationOptions { + /** + * Percentage encoded pathname section of the URL. + */ + path: string +} + +/** + * Helper to generate a type safe version of the {@link RouteLocationAsPath} type. * @internal */ export interface RouteLocationAsPathTyped< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric, + RouteMap extends RouteMapGeneric = RouteMapGeneric, Name extends keyof RouteMap = keyof RouteMap -> extends RouteQueryAndHash, - RouteLocationOptions { +> extends RouteLocationAsPathGeneric { path: _LiteralUnion // // allows to check for .path and other properties that exist in different route location types @@ -130,101 +191,111 @@ export interface RouteLocationAsPathTyped< * @internal */ export type RouteLocationAsPathTypedList< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric + RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationAsPathTyped } /** - * Same as {@link RouteLocationAsPathTyped} but as a string literal. - * @internal + * Generic version of {@link RouteLocationResolved}. It is used when no {@link RouteMap} is provided. */ -export type RouteLocationAsString< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric -> = _LiteralUnion +export interface RouteLocationResolvedGeneric extends RouteLocationGeneric { + /** + * Resolved `href` for the route location that will be set on the ``. + */ + href: string +} /** - * Type safe version of a resolved route location returned by `router.resolve()`. - * @see {@link RouteLocationTyped} + * Helper to generate a type safe version of the {@link RouteLocationResolved} type. * @internal */ export interface RouteLocationResolvedTyped< - RouteMap extends _RouteMapGeneric, + RouteMap extends RouteMapGeneric, Name extends keyof RouteMap > extends RouteLocationTyped { href: string } /** - * Record of all the resolved routes. - * @see {@link RouteLocationResolvedTyped} + * List of all possible {@link RouteLocationResolved} indexed by the route name. * @internal */ export type RouteLocationResolvedTypedList< - RouteMap extends _RouteMapGeneric = _RouteMapGeneric + RouteMap extends RouteMapGeneric = RouteMapGeneric > = { [N in keyof RouteMap]: RouteLocationResolvedTyped } /** - * Type safe versions of types that are exposed by vue-router + * Type safe versions of types that are exposed by vue-router. We have to use a generic check to allow for names to be `undefined` when no `RouteMap` is provided. */ /** - * Type safe version of `RouteLocationNormalized`. Accepts the name of the route as a type parameter. - * @see {@link RouteLocationNormalized} - */ -export type _RouteLocationNormalized< - Name extends RouteRecordName = RouteRecordName -> = RouteLocationNormalizedTypedList[Name] - -/** - * Type safe version of `RouteLocationNormalizedLoaded`. Accepts the name of the route as a type parameter. - * @see {@link RouteLocationNormalizedLoaded} + * {@link RouteLocationRaw} resolved using the matcher */ -export type _RouteLocationNormalizedLoaded< - Name extends RouteRecordName = RouteRecordName -> = RouteLocationNormalizedLoadedTypedList[Name] +export type RouteLocation = + RouteMapGeneric extends RouteMap + ? RouteLocationGeneric + : RouteLocationTypedList[Name] /** - * Type safe version of `RouteLocationAsRelative`. Accepts the name of the route as a type parameter. - * @see {@link RouteLocationAsRelative} + * Similar to {@link RouteLocation} but its + * {@link RouteLocationNormalizedTyped.matched `matched` property} cannot contain redirect records */ -export type _RouteLocationAsRelativePath< - Name extends RouteRecordName = RouteRecordName -> = RouteLocationAsRelativeTypedList[Name] +export type RouteLocationNormalized< + Name extends keyof RouteMap = keyof RouteMap +> = RouteMapGeneric extends RouteMap + ? RouteLocationNormalizedGeneric + : RouteLocationNormalizedTypedList[Name] /** - * Type safe version of `RouteLocationResolved` (the returned route of `router.resolve()`). - * Allows passing the name of the route to be passed as a generic. - * @see {@link Router['resolve']} + * Similar to {@link RouteLocationNormalized} but its `components` do not contain any function to lazy load components. + * In other words, it's ready to be rendered by ``. + * @see {@link RouteLocationNormalized} */ -export type _RouteLocationResolved< +export type RouteLocationNormalizedLoaded< Name extends keyof RouteMap = keyof RouteMap -> = RouteLocationResolvedTypedList[Name] +> = RouteMapGeneric extends RouteMap + ? RouteLocationNormalizedLoadedGeneric + : RouteLocationNormalizedLoadedTypedList[Name] /** - * {@link RouteLocationRaw} resolved using the matcher - * @see {@link RouteLocation} + * Route location relative to the current location. It accepts other properties than `path` like `params`, `query` and + * `hash` to conveniently change them. */ -export type RouteLocation = - RouteLocationTypedList[Name] +export type RouteLocationAsRelative< + Name extends keyof RouteMap = keyof RouteMap +> = RouteMapGeneric extends RouteMap + ? RouteLocationAsRelativeGeneric + : RouteLocationAsRelativeTypedList[Name] /** - * Type safe version of {@link `RouteLocationRaw`} . Allows passing the name of the route to be passed as a generic. - * @see {@link RouteLocationRaw} + * Route location resolved with `router.resolve()`. + * @see {@link Router['resolve'] | `router.resolve()`} */ -export type _RouteLocationRaw = - | RouteLocationAsString - | RouteLocationAsRelativeTypedList[Name] - | RouteLocationAsPathTypedList[Name] +export type RouteLocationResolved< + Name extends keyof RouteMap = keyof RouteMap +> = RouteMapGeneric extends RouteMap + ? RouteLocationResolvedGeneric + : RouteLocationResolvedTypedList[Name] /** - * Generate a type safe params for a route location. Requires the name of the route to be passed as a generic. - * @see {@link RouteParams} + * Same as {@link RouteLocationAsPathTyped} but as a string literal. + * @internal */ -export type _RouteParams = - RouteMap[Name]['params'] +export type RouteLocationAsString< + RouteMap extends RouteMapGeneric = RouteMapGeneric +> = RouteMapGeneric extends RouteMap + ? string + : _LiteralUnion /** - * Generate a type safe raw params for a route location. Requires the name of the route to be passed as a generic. - * @see {@link RouteParamsRaw} + * Route location that can be passed to `router.push()` and other user-facing APIs. */ -export type _RouteParamsRaw = - RouteMap[Name]['paramsRaw'] +export type RouteLocationRaw = + RouteMapGeneric extends RouteMap + ? + | RouteLocationAsString + | RouteLocationAsRelativeGeneric + | RouteLocationAsPathGeneric + : + | RouteLocationAsString + | RouteLocationAsRelativeTypedList[Name] + | RouteLocationAsPathTypedList[Name] diff --git a/packages/router/src/typed-routes/route-map.ts b/packages/router/src/typed-routes/route-map.ts index 7257c0f7..b2601409 100644 --- a/packages/router/src/typed-routes/route-map.ts +++ b/packages/router/src/typed-routes/route-map.ts @@ -1,5 +1,9 @@ import type { TypesConfig } from '../config' -import type { RouteMeta, RouteParams, RouteParamsRaw } from '../types' +import type { + RouteMeta, + RouteParamsGeneric, + RouteParamsRawGeneric, +} from '../types' import type { RouteRecord } from '../matcher/types' /** @@ -7,11 +11,12 @@ import type { RouteRecord } from '../matcher/types' * @see {@link RouteRecord} */ export interface RouteRecordInfo< + // the name cannot be nullish here as that would not allow type narrowing Name extends string | symbol = string, Path extends string = string, // TODO: could probably be inferred from the Params - ParamsRaw extends RouteParamsRaw = RouteParamsRaw, - Params extends RouteParams = RouteParams, + ParamsRaw extends RouteParamsRawGeneric = RouteParamsRawGeneric, + Params extends RouteParamsGeneric = RouteParamsGeneric, Meta extends RouteMeta = RouteMeta > { name: Name @@ -23,17 +28,16 @@ export interface RouteRecordInfo< } /** - * Convenience type to get the typed RouteMap or a generic one if not provided. + * 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. */ export type RouteMap = TypesConfig extends Record< 'RouteNamedMap', infer RouteNamedMap > ? RouteNamedMap - : _RouteMapGeneric + : RouteMapGeneric /** - * Generic version of the RouteMap. - * @internal + * Generic version of the `RouteMap`. */ -export type _RouteMapGeneric = Record +export type RouteMapGeneric = Record diff --git a/packages/router/src/typed-routes/route-records.ts b/packages/router/src/typed-routes/route-records.ts index 3a6247e5..0cd6d148 100644 --- a/packages/router/src/typed-routes/route-records.ts +++ b/packages/router/src/typed-routes/route-records.ts @@ -1,8 +1,26 @@ -import { RouteLocation, _RouteLocationRaw } from './route-location' +import { + RouteLocation, + RouteLocationNormalized, + RouteLocationRaw, +} from './route-location' +import { RouteMap } from './route-map' /** * @internal */ export type RouteRecordRedirectOption = - | _RouteLocationRaw - | ((to: RouteLocation) => _RouteLocationRaw) + | RouteLocationRaw + | ((to: RouteLocation) => RouteLocationRaw) + +/** + * Possible values for a route record **after normalization** + */ +export type RouteRecordNameGeneric = string | symbol | undefined + +/** + * @internal + */ +export type _RouteRecordProps = + | boolean + | Record + | ((to: RouteLocationNormalized) => Record) diff --git a/packages/router/src/types/index.ts b/packages/router/src/types/index.ts index 2112208d..5281a2f4 100644 --- a/packages/router/src/types/index.ts +++ b/packages/router/src/types/index.ts @@ -1,16 +1,17 @@ -import { LocationQuery, LocationQueryRaw } from '../query' -import { PathParserOptions } from '../matcher' -import { Ref, ComponentPublicInstance, Component, DefineComponent } from 'vue' -import { RouteRecord, RouteRecordNormalized } from '../matcher/types' -import { HistoryState } from '../history/common' -import { NavigationFailure } from '../errors' +import type { LocationQuery, LocationQueryRaw } from '../query' +import type { PathParserOptions } from '../matcher' +import type { Ref, Component, DefineComponent } from 'vue' +import type { RouteRecord, RouteRecordNormalized } from '../matcher/types' +import type { HistoryState } from '../history/common' import type { NavigationGuardWithThis, RouteLocation, RouteRecordName, RouteRecordRedirectOption, + _RouteRecordProps, + RouteRecordNameGeneric, } from '../typed-routes' -import { _Awaitable } from './utils' +import type { _Awaitable } from './utils' export type Lazy = () => Promise export type Override = Pick> & U @@ -39,8 +40,11 @@ export type RouteParamValue = string * @internal */ export type RouteParamValueRaw = RouteParamValue | number | null | undefined -export type RouteParams = Record -export type RouteParamsRaw = Record< +export type RouteParamsGeneric = Record< + string, + RouteParamValue | RouteParamValue[] +> +export type RouteParamsRawGeneric = Record< string, RouteParamValueRaw | Exclude[] > @@ -70,7 +74,7 @@ export interface MatcherLocationAsName { * Ignored path property since we are dealing with a relative location. Only `undefined` is allowed. */ path?: undefined - params?: RouteParams + params?: RouteParamsGeneric } /** @@ -82,20 +86,20 @@ export interface MatcherLocationAsRelative { * Ignored path property since we are dealing with a relative location. Only `undefined` is allowed. */ path?: undefined - params?: RouteParams + params?: RouteParamsGeneric } /** * @internal */ export interface LocationAsRelativeRaw { - name?: RouteRecordName + name?: RouteRecordNameGeneric // to allow checking location.path == null /** * Ignored path property since we are dealing with a relative location. Only `undefined` is allowed. */ path?: undefined - params?: RouteParamsRaw + params?: RouteParamsRawGeneric } /** @@ -120,14 +124,6 @@ export interface RouteLocationOptions { state?: HistoryState } -/** - * User-level route location - */ -export type RouteLocationRaw = - | string - | RouteLocationPathRaw - | RouteLocationNamedRaw - /** * Route Location that can infer the necessary params based on the name. * @@ -148,7 +144,7 @@ export interface RouteLocationPathRaw MatcherLocationAsPath, RouteLocationOptions {} -// TODO: rename in next major +// TODO: rename in next major to RouteRecordMatched? export interface RouteLocationMatched extends RouteRecordNormalized { // components cannot be Lazy components: Record | null | undefined @@ -181,31 +177,6 @@ export interface _RouteLocationBase redirectedFrom: RouteLocation | undefined } -// matched contains resolved components -/** - * {@link RouteLocationRaw} with - */ -export interface RouteLocationNormalizedLoaded extends _RouteLocationBase { - /** - * Array of {@link RouteLocationMatched} containing only plain components (any - * lazy-loaded components have been loaded and were replaced inside the - * `components` object) so it can be directly used to display routes. It - * cannot contain redirect records either - */ - matched: RouteLocationMatched[] // non-enumerable -} - -/** - * Similar to {@link RouteLocation} but its - * {@link RouteLocationNormalized.matched} cannot contain redirect records - */ -export interface RouteLocationNormalized extends _RouteLocationBase { - /** - * Array of {@link RouteRecordNormalized} - */ - matched: RouteRecordNormalized[] // non-enumerable -} - /** * Allowed Component in {@link RouteLocationMatched} */ @@ -215,14 +186,6 @@ export type RouteComponent = Component | DefineComponent */ export type RawRouteComponent = RouteComponent | Lazy -/** - * @internal - */ -export type _RouteRecordProps = - | boolean - | Record - | ((to: RouteLocationNormalized) => Record) - // TODO: could this be moved to matcher? /** * Internal type for common properties among all kind of {@link RouteRecordRaw}. @@ -424,7 +387,7 @@ export interface MatcherLocation { /** * Object of decoded params extracted from the `path`. */ - params: RouteParams + params: RouteParamsGeneric /** * Merged `meta` properties from all the matched route records. @@ -439,55 +402,6 @@ export interface MatcherLocation { matched: RouteRecord[] // non-enumerable } -export interface NavigationGuardNext { - (): void - (error: Error): void - (location: RouteLocationRaw): void - (valid: boolean | undefined): void - (cb: NavigationGuardNextCallback): void - /** - * Allows to detect if `next` isn't called in a resolved guard. Used - * internally in DEV mode to emit a warning. Commented out to simplify - * typings. - * @internal - */ - // _called: boolean -} - -export type NavigationGuardNextCallback = ( - vm: ComponentPublicInstance -) => unknown - -export type NavigationGuardReturn = - | void - | Error - | RouteLocationRaw - | boolean - // FIXME: this one is only allowed in options api - | NavigationGuardNextCallback - -/** - * Navigation guard. See [Navigation - * Guards](/guide/advanced/navigation-guards.md). - */ -export interface NavigationGuard { - ( - // TODO: we could maybe add extra information like replace: true/false - to: RouteLocationNormalized, - from: RouteLocationNormalizedLoaded, - next: NavigationGuardNext - // FIXME: this one shouldn't allow returning () => ... - ): _Awaitable -} - -export interface NavigationHookAfter { - ( - to: RouteLocationNormalized, - from: RouteLocationNormalized, - failure?: NavigationFailure | void - ): any -} - export * from './typeGuards' export type Mutable = { diff --git a/packages/router/src/types/typeGuards.ts b/packages/router/src/types/typeGuards.ts index 97d55281..7eac281d 100644 --- a/packages/router/src/types/typeGuards.ts +++ b/packages/router/src/types/typeGuards.ts @@ -1,9 +1,9 @@ -import type { RouteLocationRaw } from '../typed-routes' +import type { RouteLocationRaw, RouteRecordName } from '../typed-routes' export function isRouteLocation(route: any): route is RouteLocationRaw { return typeof route === 'string' || (route && typeof route === 'object') } -export function isRouteName(name: any): name is string | symbol { +export function isRouteName(name: any): name is RouteRecordName { return typeof name === 'string' || typeof name === 'symbol' } diff --git a/packages/router/src/useApi.ts b/packages/router/src/useApi.ts index e473c87b..98843001 100644 --- a/packages/router/src/useApi.ts +++ b/packages/router/src/useApi.ts @@ -19,6 +19,5 @@ export function useRouter(): Router { export function useRoute( _name?: Name ): RouteLocationNormalizedLoaded { - // @ts-expect-error: FIXME: name mismatch issue return inject(routeLocationKey)! } diff --git a/packages/router/src/utils/index.ts b/packages/router/src/utils/index.ts index af90cb5c..cb5ac7bc 100644 --- a/packages/router/src/utils/index.ts +++ b/packages/router/src/utils/index.ts @@ -1,7 +1,7 @@ import { - RouteParams, + RouteParamsGeneric, RouteComponent, - RouteParamsRaw, + RouteParamsRawGeneric, RouteParamValueRaw, } from '../types' @@ -15,9 +15,9 @@ export const assign = Object.assign export function applyToParams( fn: (v: string | number | null | undefined) => string, - params: RouteParamsRaw | undefined -): RouteParams { - const newParams: RouteParams = {} + params: RouteParamsRawGeneric | undefined +): RouteParamsGeneric { + const newParams: RouteParamsGeneric = {} for (const key in params) { const value = params[key]