Skip to content

Commit 7f94f0a

Browse files
authored
fix(NODE-4583): revert nested union type support (#3383)
1 parent 6a86553 commit 7f94f0a

File tree

3 files changed

+85
-82
lines changed

3 files changed

+85
-82
lines changed

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ export type {
324324
KeysOfOtherType,
325325
MatchKeysAndValues,
326326
NestedPaths,
327+
NestedPathsOfType,
327328
NonObjectIdLikeDocument,
328329
NotAcceptedFields,
329330
NumericType,

src/mongo_types.ts

+80-78
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ export type WithoutId<TSchema> = Omit<TSchema, '_id'>;
6868
export type Filter<TSchema> =
6969
| Partial<TSchema>
7070
| ({
71-
[Property in Join<NestedPaths<WithId<TSchema>, true>, '.'>]?: Condition<
72-
PropertyType<WithId<TSchema>, Property, true>
71+
[Property in Join<NestedPaths<WithId<TSchema>>, '.'>]?: Condition<
72+
PropertyType<WithId<TSchema>, Property>
7373
>;
7474
} & RootFilterOperators<WithId<TSchema>>);
7575

@@ -261,9 +261,19 @@ export type OnlyFieldsOfType<TSchema, FieldType = any, AssignableType = FieldTyp
261261
>;
262262

263263
/** @public */
264-
export type MatchKeysAndValues<TSchema> = Readonly<{
265-
[Property in Join<NestedPaths<TSchema, false>, '.'>]?: PropertyType<TSchema, Property, false>;
266-
}>;
264+
export type MatchKeysAndValues<TSchema> = Readonly<
265+
{
266+
[Property in Join<NestedPaths<TSchema>, '.'>]?: PropertyType<TSchema, Property>;
267+
} & {
268+
[Property in `${NestedPathsOfType<TSchema, any[]>}.$${`[${string}]` | ''}`]?: ArrayElement<
269+
PropertyType<TSchema, Property extends `${infer Key}.$${string}` ? Key : never>
270+
>;
271+
} & {
272+
[Property in `${NestedPathsOfType<TSchema, Record<string, any>[]>}.$${
273+
| `[${string}]`
274+
| ''}.${string}`]?: any; // Could be further narrowed
275+
}
276+
>;
267277

268278
/** @public */
269279
export type AddToSetOperators<Type> = {
@@ -464,83 +474,75 @@ export type Join<T extends unknown[], D extends string> = T extends []
464474
: string;
465475

466476
/** @public */
467-
export type PropertyType<
468-
Type,
469-
Property extends string,
470-
AllowToSkipArrayIndex extends boolean
471-
> = Type extends unknown
472-
? string extends Property
473-
? Type extends Map<string, infer MapType>
477+
export type PropertyType<Type, Property extends string> = string extends Property
478+
? unknown
479+
: Property extends keyof Type
480+
? Type[Property]
481+
: Property extends `${number}`
482+
? Type extends ReadonlyArray<infer ArrayType>
483+
? ArrayType
484+
: unknown
485+
: Property extends `${infer Key}.${infer Rest}`
486+
? Key extends `${number}`
487+
? Type extends ReadonlyArray<infer ArrayType>
488+
? PropertyType<ArrayType, Rest>
489+
: unknown
490+
: Key extends keyof Type
491+
? Type[Key] extends Map<string, infer MapType>
474492
? MapType
475-
: never
476-
:
477-
| (AllowToSkipArrayIndex extends false
478-
? never
479-
: Type extends ReadonlyArray<infer ArrayType>
480-
? PropertyType<ArrayType, Property, AllowToSkipArrayIndex>
481-
: never)
482-
| (Property extends keyof Type
483-
? Type[Property]
484-
: Property extends `${number | `$${'' | `[${string}]`}`}`
485-
? Type extends ReadonlyArray<infer ArrayType>
486-
? ArrayType
487-
: never
488-
: Property extends `${infer Key}.${infer Rest}`
489-
? Key extends `${number | `$${'' | `[${string}]`}`}`
490-
? Type extends ReadonlyArray<infer ArrayType>
491-
? PropertyType<ArrayType, Rest, AllowToSkipArrayIndex>
492-
: never
493-
: Key extends keyof Type
494-
? PropertyType<Type[Key], Rest, AllowToSkipArrayIndex>
495-
: never
496-
: never)
497-
: never;
493+
: PropertyType<Type[Key], Rest>
494+
: unknown
495+
: unknown;
498496

499497
/**
500498
* @public
501499
* returns tuple of strings (keys to be joined on '.') that represent every path into a schema
502500
* https://docs.mongodb.com/manual/tutorial/query-embedded-documents/
503501
*/
504-
export type NestedPaths<Type, AllowToSkipArrayIndex extends boolean> = Type extends unknown
505-
? Type extends
506-
| string
507-
| number
508-
| boolean
509-
| Date
510-
| RegExp
511-
| Buffer
512-
| Uint8Array
513-
| ((...args: any[]) => any)
514-
| { _bsontype: string }
515-
? never
516-
: Type extends ReadonlyArray<infer ArrayType>
517-
? [
518-
...(
519-
| (AllowToSkipArrayIndex extends true ? [] : never)
520-
| [number | `$${'' | `[${string}]`}`]
521-
),
522-
...([] | NestedPaths<ArrayType, AllowToSkipArrayIndex>)
523-
]
524-
: Type extends Map<string, any>
525-
? [string]
526-
: Type extends object
527-
? {
528-
[Key in Extract<keyof Type, string>]: Type[Key] extends Type // type of value extends the parent
529-
? [Key]
530-
: // for a recursive union type, the child will never extend the parent type.
531-
// but the parent will still extend the child
532-
Type extends Type[Key]
533-
? [Key]
534-
: Type[Key] extends ReadonlyArray<infer ArrayType> // handling recursive types with arrays
535-
? Type extends ArrayType // is the type of the parent the same as the type of the array?
536-
? [Key] // yes, it's a recursive array type
537-
: // for unions, the child type extends the parent
538-
ArrayType extends Type
539-
? [Key] // we have a recursive array union
540-
: // child is an array, but it's not a recursive array
541-
[Key, ...([] | NestedPaths<Type[Key], AllowToSkipArrayIndex>)]
542-
: // child is not structured the same as the parent
543-
[Key, ...([] | NestedPaths<Type[Key], AllowToSkipArrayIndex>)];
544-
}[Extract<keyof Type, string>]
545-
: never
546-
: never;
502+
export type NestedPaths<Type> = Type extends
503+
| string
504+
| number
505+
| boolean
506+
| Date
507+
| RegExp
508+
| Buffer
509+
| Uint8Array
510+
| ((...args: any[]) => any)
511+
| { _bsontype: string }
512+
? []
513+
: Type extends ReadonlyArray<infer ArrayType>
514+
? [] | [number, ...NestedPaths<ArrayType>]
515+
: Type extends Map<string, any>
516+
? [string]
517+
: Type extends object
518+
? {
519+
[Key in Extract<keyof Type, string>]: Type[Key] extends Type // type of value extends the parent
520+
? [Key]
521+
: // for a recursive union type, the child will never extend the parent type.
522+
// but the parent will still extend the child
523+
Type extends Type[Key]
524+
? [Key]
525+
: Type[Key] extends ReadonlyArray<infer ArrayType> // handling recursive types with arrays
526+
? Type extends ArrayType // is the type of the parent the same as the type of the array?
527+
? [Key] // yes, it's a recursive array type
528+
: // for unions, the child type extends the parent
529+
ArrayType extends Type
530+
? [Key] // we have a recursive array union
531+
: // child is an array, but it's not a recursive array
532+
[Key, ...NestedPaths<Type[Key]>]
533+
: // child is not structured the same as the parent
534+
[Key, ...NestedPaths<Type[Key]>] | [Key];
535+
}[Extract<keyof Type, string>]
536+
: [];
537+
538+
/**
539+
* @public
540+
* returns keys (strings) for every path into a schema with a value of type
541+
* https://docs.mongodb.com/manual/tutorial/query-embedded-documents/
542+
*/
543+
export type NestedPathsOfType<TSchema, Type> = KeysOfAType<
544+
{
545+
[Property in Join<NestedPaths<TSchema>, '.'>]: PropertyType<TSchema, Property>;
546+
},
547+
Type
548+
>;

test/types/community/collection/filterQuery.test-d.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,6 @@ nonSpecifiedCollection.find({
407407
}
408408
});
409409

410-
// NODE-4513: improves support for union types and array operators
411410
type MyArraySchema = {
412411
nested: { array: { a: number; b: boolean }[] };
413412
something: { a: number } | { b: boolean };
@@ -433,9 +432,10 @@ expectAssignable<Filter<MyArraySchema>>({
433432
expectAssignable<Filter<MyArraySchema>>({
434433
'something.a': 2
435434
});
436-
expectError<Filter<MyArraySchema>>({
437-
'something.a': false
438-
});
435+
// TODO: NODE-4513: Nested union types don't error in this case.
436+
// expectError<Filter<MyArraySchema>>({
437+
// 'something.a': false
438+
// });
439439
expectAssignable<Filter<MyArraySchema>>({
440440
'something.b': false
441441
});

0 commit comments

Comments
 (0)