Skip to content

Commit

Permalink
WIP: use Types.Array<> instead of vanilla array for InferSchemaType re:
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Nov 12, 2024
1 parent a0fdb9e commit eb7804a
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 48 deletions.
2 changes: 1 addition & 1 deletion test/types/docArray.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function gh13087() {
name: string;
location: {
type: 'Point';
coordinates: number[];
coordinates: Types.Array<number>;
};
}>>(points);
}
Expand Down
4 changes: 4 additions & 0 deletions test/types/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,10 @@ async function gh14026() {
new mongoose.Schema({ bar: [String] })
);

const doc = new TestModel();
expectType<Types.Array<string>>(doc.bar);
expectType<Types.Array<string>>({} as WithLevel1NestedPaths<typeof doc>['bar']);

expectType<string[]>(await TestModel.distinct('bar'));
}

Expand Down
36 changes: 18 additions & 18 deletions test/types/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,14 +414,14 @@ export function autoTypedSchema() {
customSchema?: Int8 | null;
map1?: Map<string, string> | null;
map2?: Map<string, number> | null;
array1: string[];
array2: any[];
array3: any[];
array4: any[];
array5: any[];
array6: string[];
array7?: string[] | null;
array8?: string[] | null;
array1: Types.Array<string>;
array2: Types.Array<any>;
array3: Types.Array<any>;
array4: Types.Array<any>;
array5: Types.Array<any>;
array6: Types.Array<string>;
array7?: Types.Array<string> | null;
array8?: Types.Array<string> | null;
decimal1?: Types.Decimal128 | null;
decimal2?: Types.Decimal128 | null;
decimal3?: Types.Decimal128 | null;
Expand Down Expand Up @@ -925,7 +925,7 @@ async function gh12593() {
const arrSchema = new Schema({ arr: [{ type: Schema.Types.UUID }] });

type ExampleArr = InferSchemaType<typeof arrSchema>;
expectType<{ arr: Buffer[] }>({} as ExampleArr);
expectType<{ arr: Types.Array<Buffer> }>({} as ExampleArr);
}

function gh12562() {
Expand Down Expand Up @@ -986,7 +986,7 @@ function gh12611() {
type Props = InferSchemaType<typeof firstSchema>;
expectType<{
description: string;
skills: Types.ObjectId[];
skills: Types.Array<Types.ObjectId>;
anotherField?: string | null;
}>({} as Props);
}
Expand Down Expand Up @@ -1048,7 +1048,7 @@ function gh12882() {
});
type tArrNum = InferSchemaType<typeof arrNum>;
expectType<{
fooArray: number[]
fooArray: Types.Array<number>
}>({} as tArrNum);
// Array of object with key named "type"
const arrType = new Schema({
Expand Down Expand Up @@ -1085,7 +1085,7 @@ function gh12882() {
});
type rTArrString = InferSchemaType<typeof rArrString>;
expectType<{
fooArray: string[]
fooArray: Types.Array<string>
}>({} as rTArrString);
// Readonly array of numbers using string definition
const rArrNum = new Schema({
Expand All @@ -1099,7 +1099,7 @@ function gh12882() {
});
type rTArrNum = InferSchemaType<typeof rArrNum>;
expectType<{
fooArray: number[]
fooArray: Types.Array<number>
}>({} as rTArrNum);
// Readonly array of object with key named "type"
const rArrType = new Schema({
Expand Down Expand Up @@ -1445,10 +1445,10 @@ function gh14367() {
type IUser = InferSchemaType<typeof UserSchema>;

const x: IUser = {
counts: [12],
roles: ['test'],
dates: [new Date('2016-06-01')],
flags: [true]
counts: new Types.Array<number>([12]),
roles: new Types.Array<string>(['test']),
dates: new Types.Array<Date>([new Date('2016-06-01')]),
flags: new Types.Array<boolean>([true])
};
}

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

expectType<string>(doc.location!.type);
expectType<number[]>(doc.location!.coordinates);
expectType<Types.Array<number>>(doc.location!.coordinates);
}

async function gh14902() {
Expand Down
44 changes: 27 additions & 17 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,9 +719,11 @@ declare module 'mongoose' {
? mongodb.Binary | null | undefined
: T[K] extends Types.DocumentArray<infer ItemType>
? Types.DocumentArray<BufferToBinary<ItemType>>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<SubdocType>
: BufferToBinary<T[K]>;
: T[K] extends Types.Array<infer ItemType>
? Types.Array<ItemType extends Buffer ? mongodb.Binary : ItemType>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<SubdocType>
: BufferToBinary<T[K]>;
} : T;

/**
Expand All @@ -733,10 +735,12 @@ declare module 'mongoose' {
: T[K] extends (Buffer | null | undefined)
? { type: 'buffer', data: number[] } | null | undefined
: T[K] extends Types.DocumentArray<infer ItemType>
? Types.DocumentArray<BufferToBinary<ItemType>>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<SubdocType>
: BufferToBinary<T[K]>;
? Types.DocumentArray<BufferToJSON<ItemType>>
: T[K] extends Types.Array<infer ItemType>
? Types.Array<ItemType extends Buffer ? { type: 'buffer', data: number[] } : ItemType>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<SubdocType>
: BufferToJSON<T[K]>;
} : T;

/**
Expand All @@ -749,9 +753,11 @@ declare module 'mongoose' {
? string | null | undefined
: T[K] extends Types.DocumentArray<infer ItemType>
? Types.DocumentArray<ObjectIdToString<ItemType>>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
: ObjectIdToString<T[K]>;
: T[K] extends Types.Array<infer ItemType>
? Types.Array<ItemType extends mongodb.ObjectId ? string : ItemType>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
: ObjectIdToString<T[K]>;
} : T;

/**
Expand All @@ -764,9 +770,11 @@ declare module 'mongoose' {
? string | null | undefined
: T[K] extends Types.DocumentArray<infer ItemType>
? Types.DocumentArray<DateToString<ItemType>>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<DateToString<SubdocType>>
: DateToString<T[K]>;
: T[K] extends Types.Array<infer ItemType>
? Types.Array<ItemType extends NativeDate ? string : ItemType>
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? HydratedSingleSubdocument<DateToString<SubdocType>>
: DateToString<T[K]>;
} : T;

/**
Expand All @@ -778,10 +786,12 @@ declare module 'mongoose' {
: T[K] extends (NativeDate | null | undefined)
? string | null | undefined
: T[K] extends Types.DocumentArray<infer ItemType>
? ItemType[]
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? SubdocType
: SubdocsToPOJOs<T[K]>;
? SubdocsToPOJOs<ItemType>[]
: T[K] extends Types.Array<infer ItemType>
? ItemType[]
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? SubdocType
: SubdocsToPOJOs<T[K]>;
} : T;

export type JSONSerialized<T> = SubdocsToPOJOs<
Expand Down
19 changes: 10 additions & 9 deletions types/inferschematype.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ObtainDocumentType,
DefaultTypeKey,
ObjectIdSchemaDefinition,
IfAny,
IfEquals,
DefaultSchemaOptions,
IsItRecordAndNotAny
Expand Down Expand Up @@ -252,22 +253,22 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
IfEquals<TypeHint, never,
PathValueType extends Schema ? InferSchemaType<PathValueType> :
PathValueType extends (infer Item)[] ?
IfEquals<Item, never, any[], Item extends Schema ?
IfEquals<Item, never, Types.Array<any>, Item extends Schema ?
// If Item is a schema, infer its type.
Types.DocumentArray<InferSchemaType<Item>> :
Item extends Record<TypeKey, any> ?
Item[TypeKey] extends Function | String ?
// If Item has a type key that's a string or a callable, it must be a scalar,
// so we can directly obtain its path type.
ObtainDocumentPathType<Item, TypeKey>[] :
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
// If the type key isn't callable, then this is an array of objects, in which case
// we need to call ObtainDocumentType to correctly infer its type.
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
IsSchemaTypeFromBuiltinClass<Item> extends true ?
ObtainDocumentPathType<Item, TypeKey>[] :
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
IsItRecordAndNotAny<Item> extends true ?
Item extends Record<string, never> ?
ObtainDocumentPathType<Item, TypeKey>[] :
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
ObtainDocumentPathType<Item, TypeKey>[]
>:
Expand All @@ -276,13 +277,13 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
Types.DocumentArray<InferSchemaType<Item>> :
Item extends Record<TypeKey, any> ?
Item[TypeKey] extends Function | String ?
ObtainDocumentPathType<Item, TypeKey>[] :
ObtainDocumentType<Item, any, { typeKey: TypeKey }>[]:
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
Types.Array<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
IsSchemaTypeFromBuiltinClass<Item> extends true ?
ObtainDocumentPathType<Item, TypeKey>[] :
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
IsItRecordAndNotAny<Item> extends true ?
Item extends Record<string, never> ?
ObtainDocumentPathType<Item, TypeKey>[] :
Types.Array<ObtainDocumentPathType<Item, TypeKey>> :
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
ObtainDocumentPathType<Item, TypeKey>[]
>:
Expand All @@ -309,7 +310,7 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
PathValueType extends MapConstructor | 'Map' ? Map<string, ResolvePathType<Options['of']>> :
IfEquals<PathValueType, typeof Schema.Types.Map> extends true ? Map<string, ResolvePathType<Options['of']>> :
PathValueType extends ArrayConstructor ? any[] :
PathValueType extends ArrayConstructor ? Types.Array<any> :
PathValueType extends typeof Schema.Types.Mixed ? any:
IfEquals<PathValueType, ObjectConstructor> extends true ? any:
IfEquals<PathValueType, {}> extends true ? any:
Expand Down
2 changes: 2 additions & 0 deletions types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ declare module 'mongoose' {

namespace Types {
class Array<T> extends global.Array<T> {
constructor(values: any[]);

/** Pops the array atomically at most one time per document `save()`. */
$pop(): T;

Expand Down
10 changes: 7 additions & 3 deletions types/utility.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ declare module 'mongoose' {
[P in keyof T as P extends K ? never : P]: T[P];
};

type Unpacked<T> = T extends (infer U)[] ?
U :
T extends ReadonlyArray<infer U> ? U : T;
type Unpacked<T> = T extends Types.Array<infer U>
? U
: T extends (infer U)[]
? U
: T extends ReadonlyArray<infer U>
? U
: T;

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

0 comments on commit eb7804a

Please sign in to comment.