From: Eduardo San Martin Morote Date: Mon, 16 May 2022 13:22:43 +0000 (+0200) Subject: refactor: use type safe isArray X-Git-Tag: v4.1.0~94 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34c27d6505970e552e673604a2ca83ce7c2a6858;p=thirdparty%2Fvuejs%2Frouter.git refactor: use type safe isArray --- diff --git a/src/RouterLink.ts b/src/RouterLink.ts index 79bad416..9e187221 100644 --- a/src/RouterLink.ts +++ b/src/RouterLink.ts @@ -36,7 +36,7 @@ import { isSameRouteLocationParams, isSameRouteRecord } from './location' import { routerKey, routeLocationKey } from './injectionSymbols' import { RouteRecord } from './matcher/types' import { NavigationFailure } from './errors' -import { isBrowser, noop } from './utils' +import { isArray, isBrowser, noop } from './utils' import { RouterTyped } from './typedRouter' export interface RouterLinkOptions { @@ -303,7 +303,7 @@ function includesParams( if (innerValue !== outerValue) return false } else { if ( - !Array.isArray(outerValue) || + !isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i]) ) diff --git a/src/RouterView.ts b/src/RouterView.ts index 4c2eca48..985e29fb 100644 --- a/src/RouterView.ts +++ b/src/RouterView.ts @@ -26,7 +26,7 @@ import { viewDepthKey, routerViewLocationKey, } from './injectionSymbols' -import { assign, isBrowser } from './utils' +import { assign, isArray, isBrowser } from './utils' import { warn } from './warning' import { isSameRouteRecord } from './location' @@ -182,7 +182,7 @@ export const RouterViewImpl = /*#__PURE__*/ defineComponent({ meta: matchedRoute.meta, } - const internalInstances = Array.isArray(component.ref) + const internalInstances = isArray(component.ref) ? component.ref.map(r => r.i) : [component.ref.i] diff --git a/src/devtools.ts b/src/devtools.ts index 7aac3d8a..a7d4f4e1 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -17,7 +17,7 @@ import { Router } from './router' import { UseLinkDevtoolsContext } from './RouterLink' import { RouterViewDevtoolsContext } from './RouterView' import { RouteLocationNormalized } from './types' -import { assign } from './utils' +import { assign, isArray } from './utils' function formatRouteLocation( routeLocation: RouteLocationNormalized, @@ -101,7 +101,7 @@ export function addDevtools(app: App, router: Router, matcher: RouterMatcher) { }) } // if multiple useLink are used - if (Array.isArray(componentInstance.__vrl_devtools)) { + if (isArray(componentInstance.__vrl_devtools)) { componentInstance.__devtoolsApi = api ;( componentInstance.__vrl_devtools as UseLinkDevtoolsContext[] diff --git a/src/location.ts b/src/location.ts index 78efa330..8ba3caa6 100644 --- a/src/location.ts +++ b/src/location.ts @@ -6,6 +6,7 @@ import { } from './types' import { RouteRecord } from './matcher/types' import { warn } from './warning' +import { isArray } from './utils' /** * Location object returned by {@link `parseURL`}. @@ -168,9 +169,9 @@ function isSameRouteLocationParamsValue( a: RouteParamValue | readonly RouteParamValue[], b: RouteParamValue | readonly RouteParamValue[] ): boolean { - return Array.isArray(a) + return isArray(a) ? isEquivalentArray(a, b) - : Array.isArray(b) + : isArray(b) ? isEquivalentArray(b, a) : a === b } @@ -182,8 +183,8 @@ function isSameRouteLocationParamsValue( * @param a - array of values * @param b - array of values or a single value */ -function isEquivalentArray(a: T[], b: T[] | T): boolean { - return Array.isArray(b) +function isEquivalentArray(a: readonly T[], b: readonly T[] | T): boolean { + return isArray(b) ? a.length === b.length && a.every((value, i) => value === b[i]) : a.length === 1 && a[0] === b } diff --git a/src/matcher/pathParserRanker.ts b/src/matcher/pathParserRanker.ts index 57dd0884..605d2326 100644 --- a/src/matcher/pathParserRanker.ts +++ b/src/matcher/pathParserRanker.ts @@ -1,5 +1,5 @@ import { Token, TokenType } from './pathTokenizer' -import { assign } from '../utils' +import { assign, isArray } from '../utils' export type PathParams = Record @@ -244,11 +244,13 @@ export function tokensToParser( const param: string | readonly string[] = value in params ? params[value] : '' - if (Array.isArray(param) && !repeatable) + if (isArray(param) && !repeatable) { throw new Error( `Provided param "${value}" is an array but it is not repeatable (* or + modifiers)` ) - const text: string = Array.isArray(param) + } + + const text: string = isArray(param) ? (param as string[]).join('/') : (param as string) if (!text) { diff --git a/src/query.ts b/src/query.ts index 21142e1c..d315a84b 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,4 +1,5 @@ import { decode, encodeQueryKey, encodeQueryValue, PLUS_RE } from './encoding' +import { isArray } from './utils' /** * Possible values in normalized {@link LocationQuery}. `null` renders the query @@ -27,7 +28,7 @@ export type LocationQueryValueRaw = LocationQueryValue | number | undefined */ export type LocationQuery = Record< string, - LocationQueryValue | LocationQueryValue[] + LocationQueryValue | readonly LocationQueryValue[] > /** * Loose {@link LocationQuery} object that can be passed to functions like @@ -38,7 +39,7 @@ export type LocationQuery = Record< */ export type LocationQueryRaw = Record< string | number, - LocationQueryValueRaw | LocationQueryValueRaw[] + LocationQueryValueRaw | readonly LocationQueryValueRaw[] > /** @@ -68,10 +69,11 @@ export function parseQuery(search: string): LocationQuery { if (key in query) { // an extra variable for ts types let currentValue = query[key] - if (!Array.isArray(currentValue)) { + if (!isArray(currentValue)) { currentValue = query[key] = [currentValue] } - currentValue.push(value) + // we force the modification + ;(currentValue as LocationQueryValue[]).push(value) } else { query[key] = value } @@ -101,7 +103,7 @@ export function stringifyQuery(query: LocationQueryRaw): string { continue } // keep null values - const values: LocationQueryValueRaw[] = Array.isArray(value) + const values: LocationQueryValueRaw[] = isArray(value) ? value.map(v => v && encodeQueryValue(v)) : [value && encodeQueryValue(value)] @@ -135,7 +137,7 @@ export function normalizeQuery( for (const key in query) { const value = query[key] if (value !== undefined) { - normalizedQuery[key] = Array.isArray(value) + normalizedQuery[key] = isArray(value) ? value.map(v => (v == null ? null : '' + v)) : value == null ? value diff --git a/src/router.ts b/src/router.ts index dbe6b308..7f0f9d1f 100644 --- a/src/router.ts +++ b/src/router.ts @@ -34,7 +34,7 @@ import { NavigationRedirectError, isNavigationFailure, } from './errors' -import { applyToParams, isBrowser, assign, noop } from './utils' +import { applyToParams, isBrowser, assign, noop, isArray } from './utils' import { useCallbacks } from './utils/callbacks' import { encodeParam, decode, encodeHash } from './encoding' import { @@ -859,7 +859,7 @@ export function createRouter( for (const record of to.matched) { // do not trigger beforeEnter on reused views if (record.beforeEnter && !from.matched.includes(record)) { - if (Array.isArray(record.beforeEnter)) { + if (isArray(record.beforeEnter)) { for (const beforeEnter of record.beforeEnter) guards.push(guardToPromiseFn(beforeEnter, to, from)) } else { diff --git a/src/utils/index.ts b/src/utils/index.ts index 1e5576af..af90cb5c 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -21,7 +21,7 @@ export function applyToParams( for (const key in params) { const value = params[key] - newParams[key] = Array.isArray(value) + newParams[key] = isArray(value) ? value.map(fn) : fn(value as Exclude) } @@ -30,3 +30,10 @@ export function applyToParams( } export const noop = () => {} + +/** + * Typesafe alternative to Array.isArray + * https://github.com/microsoft/TypeScript/pull/48228 + */ +export const isArray: (arg: ArrayLike | any) => arg is ReadonlyArray = + Array.isArray