File tree Expand file tree Collapse file tree 4 files changed +48
-3
lines changed Expand file tree Collapse file tree 4 files changed +48
-3
lines changed Original file line number Diff line number Diff line change @@ -161,13 +161,15 @@ Shortcut for sending JSON. Use this instead of the `body` option. Accepts any pl
161
161
162
162
##### searchParams
163
163
164
- Type: ` string | object<string, string | number | boolean> | Array<Array<string | number | boolean>> | URLSearchParams ` \
164
+ Type: ` string | object<string, string | number | boolean | undefined > | Array<Array<string | number | boolean>> | URLSearchParams ` \
165
165
Default: ` '' `
166
166
167
167
Search parameters to include in the request URL. Setting this will override all existing search parameters in the input URL.
168
168
169
169
Accepts any value supported by [ ` URLSearchParams() ` ] ( https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams ) .
170
170
171
+ When passing an object, ` undefined ` values are automatically filtered out, while ` null ` values are preserved and converted to the string ` 'null' ` .
172
+
171
173
##### prefixUrl
172
174
173
175
Type: ` string | URL `
Original file line number Diff line number Diff line change @@ -130,6 +130,18 @@ export class Ky {
130
130
return result ;
131
131
}
132
132
133
+ // eslint-disable-next-line unicorn/prevent-abbreviations
134
+ static #normalizeSearchParams( searchParams : any ) : any {
135
+ // Filter out undefined values from plain objects
136
+ if ( searchParams && typeof searchParams === 'object' && ! Array . isArray ( searchParams ) && ! ( searchParams instanceof URLSearchParams ) ) {
137
+ return Object . fromEntries (
138
+ Object . entries ( searchParams ) . filter ( ( [ , value ] ) => value !== undefined ) ,
139
+ ) ;
140
+ }
141
+
142
+ return searchParams ;
143
+ }
144
+
133
145
public request : Request ;
134
146
protected abortController ?: AbortController ;
135
147
protected _retryCount = 0 ;
@@ -199,7 +211,7 @@ export class Ky {
199
211
// eslint-disable-next-line unicorn/prevent-abbreviations
200
212
const textSearchParams = typeof this . _options . searchParams === 'string'
201
213
? this . _options . searchParams . replace ( / ^ \? / , '' )
202
- : new URLSearchParams ( this . _options . searchParams as unknown as SearchParamsInit ) . toString ( ) ;
214
+ : new URLSearchParams ( Ky . #normalizeSearchParams ( this . _options . searchParams ) as unknown as SearchParamsInit ) . toString ( ) ;
203
215
// eslint-disable-next-line unicorn/prevent-abbreviations
204
216
const searchParams = '?' + textSearchParams ;
205
217
const url = this . request . url . replace ( / (?: \? .* ?) ? (? = # | $ ) / , searchParams ) ;
Original file line number Diff line number Diff line change @@ -6,7 +6,7 @@ import type {RetryOptions} from './retry.js';
6
6
export type SearchParamsInit = string | string [ ] [ ] | Record < string , string > | URLSearchParams | undefined ;
7
7
8
8
// eslint-disable-next-line unicorn/prevent-abbreviations
9
- export type SearchParamsOption = SearchParamsInit | Record < string , string | number | boolean > | Array < Array < string | number | boolean > > ;
9
+ export type SearchParamsOption = SearchParamsInit | Record < string , string | number | boolean | undefined > | Array < Array < string | number | boolean > > ;
10
10
11
11
export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete' ;
12
12
@@ -88,6 +88,8 @@ export type KyOptions = {
88
88
Search parameters to include in the request URL. Setting this will override all existing search parameters in the input URL.
89
89
90
90
Accepts any value supported by [`URLSearchParams()`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams).
91
+
92
+ When passing an object, `undefined` values are automatically filtered out, while `null` values are preserved and converted to the string `'null'`.
91
93
*/
92
94
searchParams ?: SearchParamsOption ;
93
95
Original file line number Diff line number Diff line change @@ -406,6 +406,35 @@ test('searchParams option', async t => {
406
406
await server . close ( ) ;
407
407
} ) ;
408
408
409
+ test ( 'searchParams option with undefined values' , async t => {
410
+ const server = await createHttpTestServer ( ) ;
411
+
412
+ server . get ( '/' , ( request , response ) => {
413
+ response . end ( request . url . slice ( 1 ) ) ;
414
+ } ) ;
415
+
416
+ const objectWithUndefined = {
417
+ cats : 'meow' ,
418
+ dogs : undefined ,
419
+ opossums : 'false' ,
420
+ birds : undefined ,
421
+ } ;
422
+
423
+ const objectWithNull = {
424
+ cats : 'meow' ,
425
+ dogs : null as any ,
426
+ opossums : 'false' ,
427
+ } ;
428
+
429
+ // Undefined values should be filtered out
430
+ t . is ( await ky ( server . url , { searchParams : objectWithUndefined } ) . text ( ) , '?cats=meow&opossums=false' ) ;
431
+
432
+ // Null values should be preserved as string "null"
433
+ t . is ( await ky ( server . url , { searchParams : objectWithNull } ) . text ( ) , '?cats=meow&dogs=null&opossums=false' ) ;
434
+
435
+ await server . close ( ) ;
436
+ } ) ;
437
+
409
438
test ( 'throwHttpErrors option' , async t => {
410
439
const server = await createHttpTestServer ( ) ;
411
440
server . get ( '/' , ( _request , response ) => {
You can’t perform that action at this time.
0 commit comments