Repository: sindresorhus/query-string
Pull request #407 (2025-05-08 16:32:28)

FEAT: implement support for boolean type
Hey @sindresorhus , when implementing the parsing fix for PR https://github.com/sindresorhus/query-string/pull/406 I noticed it would be pretty quick to add support for a `boolean` type. This allows the user to override the behaviour of `parseBoolean`. 

I've updated the `README` and type definitions to include the new `boolean` type.

I've also updated the description of the types feature to be clearer. Let me know your thoughts!

sindresorhus: Thanks for implementing this. I think it should also accept `0` and `1` as those are commonly used as booleans.
scottenock: Good shout! I've added support for `0` and `1` when the boolean type is used.

I haven’t extended this to the parseBoolean option yet—wanted to check with you first @sindresorhus . If you think it makes sense, I’ll get it added. Otherwise, I believe the PR is good to go 💪
sindresorhus: > I haven’t extended this to the parseBoolean option yet—wanted to check with you first @sindresorhus . If you think it makes sense, I’ll get it added. Otherwise, I believe the PR is good to go 💪

No, it should not. `parseBooleans` means that it would parse numbers as booleans, even if it's meant to be a number. For example, a query parameter that could be 0, 1, 2, 3, etc.

Patch:
diff --git a/base.d.ts b/base.d.ts
index abb4e99..a008640 100644
--- a/base.d.ts
+++ b/base.d.ts
@@ -178,13 +178,13 @@ export type ParseOptions = {
 	readonly parseFragmentIdentifier?: boolean;
 
 	/**
-	Specify a pre-defined schema to be used when parsing values. The types specified will take precedence over options such as: `parseNumber`, `parseBooleans`, and `arrayFormat`.
+	Specifies a schema for parsing query values with explicit type declarations. When defined, the types provided here take precedence over general parsing options such as `parseNumbers`, `parseBooleans`, and `arrayFormat`.
 
-	Use this feature to override the type of a value. This can be useful when the type is ambiguous such as a phone number (see example 1 and 2).
+	Use this option to explicitly define the type of a specific parameter—particularly useful in cases where the type might otherwise be ambiguous (e.g., phone numbers or IDs).
 
-	It is possible to provide a custom function as the parameter type. The parameter's value will equal the function's return value (see example 4).
+	You can also provide a custom function to transform the value. The function will receive the raw string and should return the desired parsed result (see Example 4).
 
-	NOTE: Array types (`string[]` and `number[]`) will have no effect if `arrayFormat` is set to `none` (see example 5).
+	NOTE: Array types (`string[]`, `number[]`) are ignored if `arrayFormat` is set to `'none'`. (See Example 5.)
 
 	@default {}
 
@@ -217,7 +217,7 @@ export type ParseOptions = {
 	```
 
 	@example
-	Parse `age` as a number, even when `parseNumber` is false:
+	Force `age` to be parsed as a number even when `parseNumbers` is false:
 	```
 	import queryString from 'query-string';
 
@@ -230,7 +230,7 @@ export type ParseOptions = {
 	```
 
 	@example
-	Parse `age` using a custom value parser:
+	Use a custom parser function to transform the value of `age`:
 	```
 	import queryString from 'query-string';
 
@@ -243,7 +243,7 @@ export type ParseOptions = {
 	```
 
 	@example
-	Array types will have no effect when `arrayFormat` is set to `none`
+	Array types are ignored when `arrayFormat` is set to `'none'`:
 	```
 	queryString.parse('ids=001%2C002%2C003&foods=apple%2Corange%2Cmango', {
 		arrayFormat: 'none',
@@ -256,7 +256,7 @@ export type ParseOptions = {
 	```
 
 	@example
-	Parse a query utilizing all types:
+	Parse a query using multiple type definitions:
 	```
 	import queryString from 'query-string';
 
@@ -273,10 +273,24 @@ export type ParseOptions = {
 	});
 	//=> {ids: '001,002,003', items: ['1', '2', '3'], price: '22.00', numbers: [1, 2, 3], double: 10, number: 20}
 	```
+
+	@example
+	Force `flagged` to be parsed as a boolean even when `parseBooleans` is false:
+	```
+	queryString.parse('?isAdmin=true&flagged=true&isOkay=0', {
+			parseBooleans: false,
+			types: {
+					flagged: 'boolean',
+					isOkay: 'boolean',
+			},
+	});
+	//=> {isAdmin: 'true', flagged: true, isOkay: false}
+	```
+	Note: The `'boolean'` type will also convert `'0'` and `'1'` string values to booleans.
 	*/
 	readonly types?: Record<
 	string,
-	'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown)
+	'boolean' | 'number' | 'string' | 'string[]' | 'number[]' | ((value: string) => unknown)
 	>;
 };
 
diff --git a/base.js b/base.js
index e67109d..7914110 100644
--- a/base.js
+++ b/base.js
@@ -309,6 +309,14 @@ function parseValue(value, options, type) {
 		return type(value);
 	}
 
+	if (type === 'boolean' && value !== null && (value.toLowerCase() === 'true' || value.toLowerCase() === 'false')) {
+		return value.toLowerCase() === 'true';
+	}
+
+	if (type === 'boolean' && value !== null && (value.toLowerCase() === '1' || value.toLowerCase() === '0')) {
+		return value.toLowerCase() === '1';
+	}
+
 	if (type === 'string[]' && options.arrayFormat !== 'none' && typeof value === 'string') {
 		return [value];
 	}
diff --git a/readme.md b/readme.md
index ef74bea..1813507 100644
--- a/readme.md
+++ b/readme.md
@@ -193,14 +193,32 @@ Parse the value as a boolean type instead of string type if it's a boolean.
 Type: `object`\
 Default: `{}`
 
-Specify a pre-defined schema to be used when parsing values. The types specified will take precedence over options such as: `parseNumbers`, `parseBooleans`, and `arrayFormat`.
 
-Use this feature to override the type of a value. This can be useful when the type is ambiguous such as a phone number.
+Specifies a schema for parsing query values with explicit type declarations. When defined, the types provided here take precedence over general parsing options such as `parseNumbers`, `parseBooleans`, and `arrayFormat`.
+
+Use this option to explicitly define the type of a specific parameter—particularly useful in cases where the type might otherwise be ambiguous (e.g., phone numbers or IDs).
+
+You can also provide a custom function to transform the value. The function will receive the raw string and should return the desired parsed result.
 
-It is possible to provide a custom function as the parameter type. The parameter's value will equal the function's return value.
 
 Supported Types:
 
+
+- `'boolean'`: Parse `flagged` as a boolean (overriding the `parseBooleans` option):
+
+```js
+queryString.parse('?isAdmin=true&flagged=true&isOkay=0', {
+		parseBooleans: false,
+		types: {
+				flagged: 'boolean',
+				isOkay: 'boolean',
+		},
+});
+//=> {isAdmin: 'true', flagged: true, isOkay: false}
+```
+
+Note: The `'boolean'` type will also convert `'0'` and `'1'` string values to booleans.
+
 - `'string'`: Parse `phoneNumber` as a string (overriding the `parseNumbers` option):
 
 ```js
@@ -268,7 +286,7 @@ queryString.parse('?age=20&id=01234&zipcode=90210', {
 //=> {age: 40, id: '01234', zipcode: '90210'}
 ```
 
-NOTE: Array types (`string[]` and `number[]`) will have no effect if `arrayFormat` is set to `none`.
+NOTE: Array types (`string[]`, `number[]`) are ignored if `arrayFormat` is set to `'none'`.
 
 ```js
 queryString.parse('ids=001%2C002%2C003&foods=apple%2Corange%2Cmango', {


Test patch:
diff --git a/test/parse.js b/test/parse.js
index d20f540..ad25dbe 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -568,3 +568,27 @@ test('types option: single element with `{arrayFormat: "comma"}, and type: numbe
 		a: [1],
 	});
 });
+
+test('types option: can parse boolean when parseboolean is false', t => {
+	t.deepEqual(queryString.parse('a=true', {
+		parsebooleans: false,
+		types: {
+			a: 'boolean',
+		},
+	}), {
+		a: true,
+	});
+});
+
+test('types option: boolean type accepts 1 and 0 as boolean values', t => {
+	t.deepEqual(queryString.parse('a=1&b=0', {
+		parsebooleans: false,
+		types: {
+			a: 'boolean',
+			b: 'boolean',
+		},
+	}), {
+		a: true,
+		b: false,
+	});
+});