diff --git a/index.d.ts b/index.d.ts index e3558f2d..dcf6c157 100644 --- a/index.d.ts +++ b/index.d.ts @@ -13,25 +13,25 @@ export interface ParseOptions { * * * queryString.parse('foo[]=1&foo[]=2&foo[]=3', {arrayFormat: 'bracket'}); - * //=> foo: [1, 2, 3] + * //=> foo: ['1', '2', '3'] * * - `index`: Parse arrays with index representation: * * * queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'}); - * //=> foo: [1, 2, 3] + * //=> foo: ['1', '2', '3'] * * - `comma`: Parse arrays with elements separated by comma: * * * queryString.parse('foo=1,2,3', {arrayFormat: 'comma'}); - * //=> foo: [1, 2, 3] + * //=> foo: ['1', '2', '3'] * * - `none`: Parse arrays with elements using duplicate keys: * * * queryString.parse('foo=1&foo=2&foo=3'); - * //=> foo: [1, 2, 3] + * //=> foo: ['1', '2', '3'] */ readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'none'; @@ -55,10 +55,21 @@ export interface ParseOptions { */ readonly sort?: ((itemLeft: string, itemRight: string) => number) | false; + /** + * Parse the value as a number type instead of string type if it's a number. + * + * @default false + * + * @example + * + * queryString.parse('foo[]=1&foo[]=2&foo[]=3', {parseNumbers: true}); + * //=> foo: [1, 2, 3] + */ + readonly parseNumbers?: boolean; } export interface ParsedQuery { - readonly [key: string]: string | string[] | null | undefined; + readonly [key: string]: string | number | Array | null | undefined; } /** diff --git a/index.js b/index.js index 451472b0..677cc5b8 100644 --- a/index.js +++ b/index.js @@ -175,7 +175,8 @@ function parse(input, options) { options = Object.assign({ decode: true, sort: true, - arrayFormat: 'none' + arrayFormat: 'none', + parseNumbers: false }, options); const formatter = parserForArrayFormat(options); @@ -200,6 +201,10 @@ function parse(input, options) { // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters value = value === undefined ? null : decode(value, options); + if (options.parseNumbers && !Number.isNaN(Number(value))) { + value = Number(value); + } + formatter(decode(key, options), value, ret); } diff --git a/index.test-d.ts b/index.test-d.ts index 02b7f530..eddfc3ca 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -51,6 +51,9 @@ expectType( expectType( queryString.parse('?foo=bar', {arrayFormat: 'comma'}) ); +expectType( + queryString.parse('?foo=1', {parseNumbers: true}) +); // Parse URL expectType(queryString.parseUrl('?foo=bar')); @@ -70,6 +73,9 @@ expectType( expectType( queryString.parseUrl('?foo=bar', {arrayFormat: 'comma'}) ); +expectType( + queryString.parse('?foo=1', {parseNumbers: true}) +); // Extract expectType(queryString.extract('http://foo.bar/?abc=def&hij=klm')); diff --git a/readme.md b/readme.md index 13c96940..c3a5fd76 100644 --- a/readme.md +++ b/readme.md @@ -72,28 +72,28 @@ Default: `'none'` ```js queryString.parse('foo[]=1&foo[]=2&foo[]=3', {arrayFormat: 'bracket'}); -//=> foo: [1, 2, 3] +//=> foo: ['1', '2', '3'] ``` - `'index'`: Parse arrays with index representation: ```js queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'}); -//=> foo: [1, 2, 3] +//=> foo: ['1', '2', '3'] ``` - `'comma'`: Parse arrays with elements separated by comma: ```js queryString.parse('foo=1,2,3', {arrayFormat: 'comma'}); -//=> foo: [1, 2, 3] +//=> foo: ['1', '2', '3'] ``` - `'none'`: Parse arrays with elements using duplicate keys: ```js queryString.parse('foo=1&foo=2&foo=3'); -//=> foo: [1, 2, 3] +//=> foo: ['1', '2', '3'] ``` ##### sort @@ -103,6 +103,18 @@ Default: `true` Supports both `Function` as a custom sorting function or `false` to disable sorting. +##### parseNumbers + +Type: `boolean`
+Default: `false` + +```js +queryString.parse('foo[]=1&foo[]=2&foo[]=3', {parseNumbers: true}); +//=> foo: [1, 2, 3] +``` + +Parse the value as a number type instead of string type if it's a number. + ### .stringify(object, [options]) Stringify an object into a query string and sorting the keys. diff --git a/test/parse.js b/test/parse.js index cea4621e..96e82023 100644 --- a/test/parse.js +++ b/test/parse.js @@ -228,3 +228,19 @@ test('decode keys and values', t => { test('disable decoding of keys and values', t => { t.deepEqual(queryString.parse('tags=postal%20office,burger%2C%20fries%20and%20coke', {decode: false}), {tags: 'postal%20office,burger%2C%20fries%20and%20coke'}); }); + +test('number value returns as string by default', t => { + t.deepEqual(queryString.parse('foo=1'), {foo: '1'}); +}); + +test('number value returns as number if option is set', t => { + t.deepEqual(queryString.parse('foo=1', {parseNumbers: true}), {foo: 1}); + t.deepEqual(queryString.parse('foo=12.3&bar=123e-1', {parseNumbers: true}), {foo: 12.3, bar: 12.3}); + t.deepEqual(queryString.parse('foo=0x11&bar=12.00', {parseNumbers: true}), {foo: 17, bar: 12}); +}); + +test('NaN value returns as string if option is set', t => { + t.deepEqual(queryString.parse('foo=null', {parseNumbers: true}), {foo: 'null'}); + t.deepEqual(queryString.parse('foo=undefined', {parseNumbers: true}), {foo: 'undefined'}); + t.deepEqual(queryString.parse('foo=100a&bar=100', {parseNumbers: true}), {foo: '100a', bar: 100}); +});