Skip to content

Commit eb7804a

Browse files
committed
WIP: use Types.Array<> instead of vanilla array for InferSchemaType re: #14983
1 parent a0fdb9e commit eb7804a

7 files changed

+69
-48
lines changed

test/types/docArray.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function gh13087() {
7373
name: string;
7474
location: {
7575
type: 'Point';
76-
coordinates: number[];
76+
coordinates: Types.Array<number>;
7777
};
7878
}>>(points);
7979
}

test/types/models.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,10 @@ async function gh14026() {
799799
new mongoose.Schema({ bar: [String] })
800800
);
801801

802+
const doc = new TestModel();
803+
expectType<Types.Array<string>>(doc.bar);
804+
expectType<Types.Array<string>>({} as WithLevel1NestedPaths<typeof doc>['bar']);
805+
802806
expectType<string[]>(await TestModel.distinct('bar'));
803807
}
804808

test/types/schema.test.ts

+18-18
Original file line numberDiff line numberDiff line change
@@ -414,14 +414,14 @@ export function autoTypedSchema() {
414414
customSchema?: Int8 | null;
415415
map1?: Map<string, string> | null;
416416
map2?: Map<string, number> | null;
417-
array1: string[];
418-
array2: any[];
419-
array3: any[];
420-
array4: any[];
421-
array5: any[];
422-
array6: string[];
423-
array7?: string[] | null;
424-
array8?: string[] | null;
417+
array1: Types.Array<string>;
418+
array2: Types.Array<any>;
419+
array3: Types.Array<any>;
420+
array4: Types.Array<any>;
421+
array5: Types.Array<any>;
422+
array6: Types.Array<string>;
423+
array7?: Types.Array<string> | null;
424+
array8?: Types.Array<string> | null;
425425
decimal1?: Types.Decimal128 | null;
426426
decimal2?: Types.Decimal128 | null;
427427
decimal3?: Types.Decimal128 | null;
@@ -925,7 +925,7 @@ async function gh12593() {
925925
const arrSchema = new Schema({ arr: [{ type: Schema.Types.UUID }] });
926926

927927
type ExampleArr = InferSchemaType<typeof arrSchema>;
928-
expectType<{ arr: Buffer[] }>({} as ExampleArr);
928+
expectType<{ arr: Types.Array<Buffer> }>({} as ExampleArr);
929929
}
930930

931931
function gh12562() {
@@ -986,7 +986,7 @@ function gh12611() {
986986
type Props = InferSchemaType<typeof firstSchema>;
987987
expectType<{
988988
description: string;
989-
skills: Types.ObjectId[];
989+
skills: Types.Array<Types.ObjectId>;
990990
anotherField?: string | null;
991991
}>({} as Props);
992992
}
@@ -1048,7 +1048,7 @@ function gh12882() {
10481048
});
10491049
type tArrNum = InferSchemaType<typeof arrNum>;
10501050
expectType<{
1051-
fooArray: number[]
1051+
fooArray: Types.Array<number>
10521052
}>({} as tArrNum);
10531053
// Array of object with key named "type"
10541054
const arrType = new Schema({
@@ -1085,7 +1085,7 @@ function gh12882() {
10851085
});
10861086
type rTArrString = InferSchemaType<typeof rArrString>;
10871087
expectType<{
1088-
fooArray: string[]
1088+
fooArray: Types.Array<string>
10891089
}>({} as rTArrString);
10901090
// Readonly array of numbers using string definition
10911091
const rArrNum = new Schema({
@@ -1099,7 +1099,7 @@ function gh12882() {
10991099
});
11001100
type rTArrNum = InferSchemaType<typeof rArrNum>;
11011101
expectType<{
1102-
fooArray: number[]
1102+
fooArray: Types.Array<number>
11031103
}>({} as rTArrNum);
11041104
// Readonly array of object with key named "type"
11051105
const rArrType = new Schema({
@@ -1445,10 +1445,10 @@ function gh14367() {
14451445
type IUser = InferSchemaType<typeof UserSchema>;
14461446

14471447
const x: IUser = {
1448-
counts: [12],
1449-
roles: ['test'],
1450-
dates: [new Date('2016-06-01')],
1451-
flags: [true]
1448+
counts: new Types.Array<number>([12]),
1449+
roles: new Types.Array<string>(['test']),
1450+
dates: new Types.Array<Date>([new Date('2016-06-01')]),
1451+
flags: new Types.Array<boolean>([true])
14521452
};
14531453
}
14541454

@@ -1664,7 +1664,7 @@ async function gh14950() {
16641664
const doc = await TestModel.findOne().orFail();
16651665

16661666
expectType<string>(doc.location!.type);
1667-
expectType<number[]>(doc.location!.coordinates);
1667+
expectType<Types.Array<number>>(doc.location!.coordinates);
16681668
}
16691669

16701670
async function gh14902() {

types/index.d.ts

+27-17
Original file line numberDiff line numberDiff line change
@@ -719,9 +719,11 @@ declare module 'mongoose' {
719719
? mongodb.Binary | null | undefined
720720
: T[K] extends Types.DocumentArray<infer ItemType>
721721
? Types.DocumentArray<BufferToBinary<ItemType>>
722-
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
723-
? HydratedSingleSubdocument<SubdocType>
724-
: BufferToBinary<T[K]>;
722+
: T[K] extends Types.Array<infer ItemType>
723+
? Types.Array<ItemType extends Buffer ? mongodb.Binary : ItemType>
724+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
725+
? HydratedSingleSubdocument<SubdocType>
726+
: BufferToBinary<T[K]>;
725727
} : T;
726728

727729
/**
@@ -733,10 +735,12 @@ declare module 'mongoose' {
733735
: T[K] extends (Buffer | null | undefined)
734736
? { type: 'buffer', data: number[] } | null | undefined
735737
: T[K] extends Types.DocumentArray<infer ItemType>
736-
? Types.DocumentArray<BufferToBinary<ItemType>>
737-
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
738-
? HydratedSingleSubdocument<SubdocType>
739-
: BufferToBinary<T[K]>;
738+
? Types.DocumentArray<BufferToJSON<ItemType>>
739+
: T[K] extends Types.Array<infer ItemType>
740+
? Types.Array<ItemType extends Buffer ? { type: 'buffer', data: number[] } : ItemType>
741+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
742+
? HydratedSingleSubdocument<SubdocType>
743+
: BufferToJSON<T[K]>;
740744
} : T;
741745

742746
/**
@@ -749,9 +753,11 @@ declare module 'mongoose' {
749753
? string | null | undefined
750754
: T[K] extends Types.DocumentArray<infer ItemType>
751755
? Types.DocumentArray<ObjectIdToString<ItemType>>
752-
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
753-
? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
754-
: ObjectIdToString<T[K]>;
756+
: T[K] extends Types.Array<infer ItemType>
757+
? Types.Array<ItemType extends mongodb.ObjectId ? string : ItemType>
758+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
759+
? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
760+
: ObjectIdToString<T[K]>;
755761
} : T;
756762

757763
/**
@@ -764,9 +770,11 @@ declare module 'mongoose' {
764770
? string | null | undefined
765771
: T[K] extends Types.DocumentArray<infer ItemType>
766772
? Types.DocumentArray<DateToString<ItemType>>
767-
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
768-
? HydratedSingleSubdocument<DateToString<SubdocType>>
769-
: DateToString<T[K]>;
773+
: T[K] extends Types.Array<infer ItemType>
774+
? Types.Array<ItemType extends NativeDate ? string : ItemType>
775+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
776+
? HydratedSingleSubdocument<DateToString<SubdocType>>
777+
: DateToString<T[K]>;
770778
} : T;
771779

772780
/**
@@ -778,10 +786,12 @@ declare module 'mongoose' {
778786
: T[K] extends (NativeDate | null | undefined)
779787
? string | null | undefined
780788
: T[K] extends Types.DocumentArray<infer ItemType>
781-
? ItemType[]
782-
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
783-
? SubdocType
784-
: SubdocsToPOJOs<T[K]>;
789+
? SubdocsToPOJOs<ItemType>[]
790+
: T[K] extends Types.Array<infer ItemType>
791+
? ItemType[]
792+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
793+
? SubdocType
794+
: SubdocsToPOJOs<T[K]>;
785795
} : T;
786796

787797
export type JSONSerialized<T> = SubdocsToPOJOs<

types/inferschematype.d.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
ObtainDocumentType,
1313
DefaultTypeKey,
1414
ObjectIdSchemaDefinition,
15+
IfAny,
1516
IfEquals,
1617
DefaultSchemaOptions,
1718
IsItRecordAndNotAny
@@ -252,22 +253,22 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
252253
IfEquals<TypeHint, never,
253254
PathValueType extends Schema ? InferSchemaType<PathValueType> :
254255
PathValueType extends (infer Item)[] ?
255-
IfEquals<Item, never, any[], Item extends Schema ?
256+
IfEquals<Item, never, Types.Array<any>, Item extends Schema ?
256257
// If Item is a schema, infer its type.
257258
Types.DocumentArray<InferSchemaType<Item>> :
258259
Item extends Record<TypeKey, any> ?
259260
Item[TypeKey] extends Function | String ?
260261
// If Item has a type key that's a string or a callable, it must be a scalar,
261262
// so we can directly obtain its path type.
262-
ObtainDocumentPathType<Item, TypeKey>[] :
263+
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
263264
// If the type key isn't callable, then this is an array of objects, in which case
264265
// we need to call ObtainDocumentType to correctly infer its type.
265266
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
266267
IsSchemaTypeFromBuiltinClass<Item> extends true ?
267-
ObtainDocumentPathType<Item, TypeKey>[] :
268+
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
268269
IsItRecordAndNotAny<Item> extends true ?
269270
Item extends Record<string, never> ?
270-
ObtainDocumentPathType<Item, TypeKey>[] :
271+
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
271272
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
272273
ObtainDocumentPathType<Item, TypeKey>[]
273274
>:
@@ -276,13 +277,13 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
276277
Types.DocumentArray<InferSchemaType<Item>> :
277278
Item extends Record<TypeKey, any> ?
278279
Item[TypeKey] extends Function | String ?
279-
ObtainDocumentPathType<Item, TypeKey>[] :
280-
ObtainDocumentType<Item, any, { typeKey: TypeKey }>[]:
280+
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
281+
Types.Array<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
281282
IsSchemaTypeFromBuiltinClass<Item> extends true ?
282-
ObtainDocumentPathType<Item, TypeKey>[] :
283+
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
283284
IsItRecordAndNotAny<Item> extends true ?
284285
Item extends Record<string, never> ?
285-
ObtainDocumentPathType<Item, TypeKey>[] :
286+
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
286287
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
287288
ObtainDocumentPathType<Item, TypeKey>[]
288289
>:
@@ -309,7 +310,7 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
309310
IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
310311
PathValueType extends MapConstructor | 'Map' ? Map<string, ResolvePathType<Options['of']>> :
311312
IfEquals<PathValueType, typeof Schema.Types.Map> extends true ? Map<string, ResolvePathType<Options['of']>> :
312-
PathValueType extends ArrayConstructor ? any[] :
313+
PathValueType extends ArrayConstructor ? Types.Array<any> :
313314
PathValueType extends typeof Schema.Types.Mixed ? any:
314315
IfEquals<PathValueType, ObjectConstructor> extends true ? any:
315316
IfEquals<PathValueType, {}> extends true ? any:

types/types.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ declare module 'mongoose' {
77

88
namespace Types {
99
class Array<T> extends global.Array<T> {
10+
constructor(values: any[]);
11+
1012
/** Pops the array atomically at most one time per document `save()`. */
1113
$pop(): T;
1214

types/utility.d.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ declare module 'mongoose' {
3333
[P in keyof T as P extends K ? never : P]: T[P];
3434
};
3535

36-
type Unpacked<T> = T extends (infer U)[] ?
37-
U :
38-
T extends ReadonlyArray<infer U> ? U : T;
36+
type Unpacked<T> = T extends Types.Array<infer U>
37+
? U
38+
: T extends (infer U)[]
39+
? U
40+
: T extends ReadonlyArray<infer U>
41+
? U
42+
: T;
3943

4044
type UnpackedIntersection<T, U> = T extends null ? null : T extends (infer A)[]
4145
? (Omit<A, keyof U> & U)[]

0 commit comments

Comments
 (0)