Skip to content

Commit c49c3dc

Browse files
author
Yash Dayama
committed
fix(types): update Route query type definition to support null values
- Updated TypeScript and Flow type definitions to properly handle null values in query parameters - Added dedicated type tests to verify query parameter scenarios Fixes #3566
1 parent b37ac83 commit c49c3dc

File tree

5 files changed

+43
-34
lines changed

5 files changed

+43
-34
lines changed

flow/declarations.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* @flow */
2+
13
declare var document: Document;
24

35
declare class RouteRegExp extends RegExp {
@@ -18,6 +20,8 @@ declare module 'path-to-regexp' {
1820
}
1921

2022
declare type Dictionary<T> = { [key: string]: T }
23+
declare type QueryValue = string | null | Array<string | null>
24+
declare type QueryDictionary = { [key: string]: QueryValue }
2125

2226
declare type NavigationGuard = (
2327
to: Route,
@@ -84,7 +88,7 @@ declare type Location = {
8488
name?: string;
8589
path?: string;
8690
hash?: string;
87-
query?: Dictionary<string | null | Array<string | null>>;
91+
query?: QueryDictionary;
8892
params?: Dictionary<string>;
8993
append?: boolean;
9094
replace?: boolean;
@@ -96,7 +100,7 @@ declare type Route = {
96100
path: string;
97101
name: ?string;
98102
hash: string;
99-
query: Dictionary<string | null | Array<string | null>>;
103+
query: QueryDictionary;
100104
params: Dictionary<string>;
101105
fullPath: string;
102106
matched: Array<RouteRecord>;

src/util/location.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ export function normalizeLocation (
4949
? resolvePath(parsedPath.path, basePath, append || next.append)
5050
: basePath
5151

52-
const query = resolveQuery(
52+
const query: QueryDictionary = resolveQuery(
5353
parsedPath.query,
54-
next.query,
54+
next.query || {},
5555
router && router.options.parseQuery
5656
)
5757

src/util/query.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ export function decode (str: string) {
2727

2828
export function resolveQuery (
2929
query: ?string,
30-
extraQuery: Dictionary<string> = {},
30+
extraQuery: QueryDictionary = {},
3131
_parseQuery: ?Function
32-
): Dictionary<string> {
32+
): QueryDictionary {
3333
const parse = _parseQuery || parseQuery
3434
let parsedQuery
3535
try {
@@ -49,7 +49,7 @@ export function resolveQuery (
4949

5050
const castQueryParamValue = value => (value == null || typeof value === 'object' ? value : String(value))
5151

52-
function parseQuery (query: string): Dictionary<string> {
52+
function parseQuery (query: string): QueryDictionary {
5353
const res = {}
5454

5555
query = query.trim().replace(/^(\?|#|&)/, '')
@@ -75,7 +75,7 @@ function parseQuery (query: string): Dictionary<string> {
7575
return res
7676
}
7777

78-
export function stringifyQuery (obj: Dictionary<string>): string {
78+
export function stringifyQuery (obj: QueryDictionary): string {
7979
const res = obj
8080
? Object.keys(obj)
8181
.map(key => {

src/util/route.js

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,26 +94,24 @@ export function isSameRoute (a: Route, b: ?Route, onlyPath: ?boolean): boolean {
9494
}
9595

9696
function isObjectEqual (a = {}, b = {}): boolean {
97-
// handle null value #1566
9897
if (!a || !b) return a === b
99-
const aKeys = Object.keys(a).sort()
100-
const bKeys = Object.keys(b).sort()
101-
if (aKeys.length !== bKeys.length) {
102-
return false
98+
if (Array.isArray(a) && Array.isArray(b)) {
99+
return a.length === b.length && a.every((v, i) => String(v) === String(b[i]))
103100
}
104-
return aKeys.every((key, i) => {
105-
const aVal = a[key]
106-
const bKey = bKeys[i]
107-
if (bKey !== key) return false
108-
const bVal = b[key]
109-
// query values can be null and undefined
110-
if (aVal == null || bVal == null) return aVal === bVal
111-
// check nested equality
112-
if (typeof aVal === 'object' && typeof bVal === 'object') {
101+
if (a instanceof Object && b instanceof Object) {
102+
const aKeys = Object.keys(a).sort()
103+
const bKeys = Object.keys(b).sort()
104+
if (aKeys.length !== bKeys.length) return false
105+
return aKeys.every((key, i) => {
106+
const aVal = a[key]
107+
const bKey = bKeys[i]
108+
if (bKey !== key) return false
109+
const bVal = b[key]
110+
if (aVal == null || bVal == null) return aVal === bVal
113111
return isObjectEqual(aVal, bVal)
114-
}
115-
return String(aVal) === String(bVal)
116-
})
112+
})
113+
}
114+
return String(a) === String(b)
117115
}
118116

119117
export function isIncludedRoute (current: Route, target: Route): boolean {
@@ -126,11 +124,9 @@ export function isIncludedRoute (current: Route, target: Route): boolean {
126124
)
127125
}
128126

129-
function queryIncludes (current: Dictionary<string>, target: Dictionary<string>): boolean {
127+
function queryIncludes (current: QueryDictionary, target: QueryDictionary): boolean {
130128
for (const key in target) {
131-
if (!(key in current)) {
132-
return false
133-
}
129+
if (!(key in current)) return false
134130
}
135131
return true
136132
}

types/test/index.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,23 @@ router.push({
193193
foo: 'foo'
194194
},
195195
query: {
196-
bar: 'bar',
197-
empty: null,
198-
removed: undefined,
199-
withEmpty: ['1', null],
200-
foo: ['foo1', 'foo2']
196+
bar: 'bar',
197+
empty: null,
198+
removed: undefined,
199+
withEmpty: ['1', null],
200+
foo: ['foo1', 'foo2'],
201+
queryWithoutValue: null,
202+
mixedArray: [null, 'value']
201203
},
202204
hash: 'hash'
203205
})
206+
207+
const routeQuery: Route['query'] = {
208+
stringValue: 'test',
209+
nullValue: null,
210+
arrayValue: ['test', null],
211+
emptyValue: null
212+
}
204213
router.replace({ name: 'home' })
205214

206215
router.push(

0 commit comments

Comments
 (0)