Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.

Commit 63dea5b

Browse files
Fix 960 boolean field inference (#961)
Fixes #960 ### Summary This PR fixes TypeScript type inference for boolean schema fields to align with runtime behavior. Previously, boolean fields were typed as `boolean | null`, but the `BooleanDataTransformer` always converts `null` values to `false` at runtime, meaning boolean fields never actually return `null`. This change updates the type inference to correctly reflect that boolean fields always return `boolean`, eliminating a type-safety gap where TypeScript allowed `null` handling that would never execute. ### Technical Details **Changed**: `InferSchemaType` type helper in `src/Schema.ts` - Removed `InferRequiredType` wrapper from boolean type inference - Boolean fields now directly infer as `boolean` regardless of the `required` property - Other scalar types (string, number, date/time) continue to respect `required` and can still be `null` ### Breaking Changes This is technically a breaking change for TypeScript consumers, though it corrects a type-safety issue: - Code that previously handled `null` values for boolean fields will now show TypeScript errors - However, such null checks were unnecessary since `null` is transformed to `false` at runtime - Users needing true tri-state logic (true/false/null as distinct states) should use `string` type with `enum` constraint, as documented --------- Co-authored-by: Shawn McKnight <smcknight@storis.com>
1 parent 5f9bc22 commit 63dea5b

File tree

4 files changed

+11
-14
lines changed

4 files changed

+11
-14
lines changed

src/Schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ type InferArraySchemaType<
145145
/** Infer the output type of a schema type definition */
146146
type InferSchemaType<TSchemaTypeDefinition, TConstraint> =
147147
TSchemaTypeDefinition extends SchemaTypeDefinitionBoolean
148-
? InferRequiredType<TSchemaTypeDefinition, boolean>
148+
? boolean
149149
: TSchemaTypeDefinition extends SchemaTypeDefinitionString
150150
? InferRequiredType<TSchemaTypeDefinition, InferStringType<TSchemaTypeDefinition>>
151151
: TSchemaTypeDefinition extends SchemaTypeDefinitionNumber

src/__tests__/Document.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ describe('utility types', () => {
10611061
const test1: Equals<
10621062
DocumentData<typeof schema>,
10631063
{
1064-
boolean?: boolean | null;
1064+
boolean: boolean;
10651065
string?: string | null;
10661066
number?: number | null;
10671067
isoCalendarDate?: ISOCalendarDate | null;
@@ -1123,7 +1123,7 @@ describe('utility types', () => {
11231123
const test1: Equals<
11241124
DocumentData<typeof schema>,
11251125
{
1126-
booleanOptional?: boolean | null;
1126+
booleanOptional: boolean;
11271127
booleanRequired: boolean;
11281128
stringOptional?: string | null;
11291129
stringRequired: string;

src/__tests__/Query.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2403,7 +2403,7 @@ describe('utility types', () => {
24032403
{
24042404
$and?: readonly Filter<typeof schema>[];
24052405
$or?: readonly Filter<typeof schema>[];
2406-
booleanOptional?: Condition<boolean | null>;
2406+
booleanOptional?: Condition<boolean>;
24072407
booleanRequired?: Condition<boolean>;
24082408
stringOptional?: Condition<string | null>;
24092409
stringRequired?: Condition<string>;

src/__tests__/Schema.test.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -502,12 +502,9 @@ describe('utility types', () => {
502502
});
503503

504504
test('should infer boolean type', () => {
505-
// not required should be nullable
505+
// boolean fields always return boolean (null is transformed to false)
506506
const schema1 = new Schema({ booleanProp: { type: 'boolean', path: '1' } });
507-
const test1: Equals<
508-
InferDocumentObject<typeof schema1>,
509-
{ booleanProp: boolean | null }
510-
> = true;
507+
const test1: Equals<InferDocumentObject<typeof schema1>, { booleanProp: boolean }> = true;
511508
expect(test1).toBe(true);
512509

513510
// required should not be nullable
@@ -801,7 +798,7 @@ describe('utility types', () => {
801798
const test1: Equals<
802799
InferDocumentObject<typeof schema>,
803800
{
804-
booleanOptional: boolean | null;
801+
booleanOptional: boolean;
805802
booleanRequired: boolean;
806803
stringOptional: string | null;
807804
stringRequired: string;
@@ -896,11 +893,11 @@ describe('utility types', () => {
896893
});
897894

898895
test('should infer boolean type', () => {
899-
// not required should be nullable
896+
// boolean fields always return boolean (null is transformed to false)
900897
const schema1 = new Schema({ booleanProp: { type: 'boolean', path: '1' } });
901898
const test1: Equals<
902899
InferModelObject<typeof schema1>,
903-
{ _id: string; __v: string; booleanProp: boolean | null }
900+
{ _id: string; __v: string; booleanProp: boolean }
904901
> = true;
905902
expect(test1).toBe(true);
906903

@@ -1226,7 +1223,7 @@ describe('utility types', () => {
12261223
{
12271224
_id: string;
12281225
__v: string;
1229-
booleanOptional: boolean | null;
1226+
booleanOptional: boolean;
12301227
booleanRequired: boolean;
12311228
stringOptional: string | null;
12321229
stringRequired: string;
@@ -1317,7 +1314,7 @@ describe('utility types', () => {
13171314
const test1: Equals<
13181315
FlattenDocument<typeof schema>,
13191316
{
1320-
booleanOptional: boolean | null;
1317+
booleanOptional: boolean;
13211318
booleanRequired: boolean;
13221319
stringOptional: string | null;
13231320
stringRequired: string;

0 commit comments

Comments
 (0)