Skip to content

Commit d53b1c5

Browse files
authored
Merge pull request #14095 from Automattic/vkarpov15/gh-13424
types: allow defining document array using `[{ prop: String }]` syntax
2 parents 360b417 + a9c515b commit d53b1c5

File tree

3 files changed

+81
-11
lines changed

3 files changed

+81
-11
lines changed

test/types/docArray.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,19 @@ function gh13087() {
7777
};
7878
}>>(points);
7979
}
80+
81+
async function gh13424() {
82+
const subDoc = {
83+
name: { type: String, required: true },
84+
controls: { type: String, required: true }
85+
};
86+
87+
const testSchema = new Schema({
88+
question: { type: String, required: true },
89+
subDocArray: { type: [subDoc], required: true }
90+
});
91+
const TestModel = model('Test', testSchema);
92+
93+
const doc = new TestModel();
94+
expectType<Types.ObjectId | undefined>(doc.subDocArray[0]._id);
95+
}

test/types/schema.test.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -669,9 +669,9 @@ function gh12030() {
669669
username: { type: String }
670670
}
671671
]>;
672-
expectType<{
672+
expectType<Types.DocumentArray<{
673673
username?: string | null
674-
}[]>({} as A);
674+
}>>({} as A);
675675

676676
type B = ObtainDocumentType<{
677677
users: [
@@ -681,15 +681,15 @@ function gh12030() {
681681
]
682682
}>;
683683
expectType<{
684-
users: {
684+
users: Types.DocumentArray<{
685685
username?: string | null
686-
}[];
686+
}>;
687687
}>({} as B);
688688

689689
expectType<{
690-
users: {
690+
users: Types.DocumentArray<{
691691
username?: string | null
692-
}[];
692+
}>;
693693
}>({} as InferSchemaType<typeof Schema1>);
694694

695695
const Schema2 = new Schema({
@@ -1351,3 +1351,20 @@ function gh14028_statics() {
13511351
// Trigger type assertions inside statics
13521352
schema.statics.createWithFullName('John Doe');
13531353
}
1354+
1355+
function gh13424() {
1356+
const subDoc = {
1357+
name: { type: String, required: true },
1358+
controls: { type: String, required: true }
1359+
};
1360+
1361+
const testSchema = {
1362+
question: { type: String, required: true },
1363+
subDocArray: { type: [subDoc], required: true }
1364+
};
1365+
1366+
const TestModel = model('TestModel', new Schema(testSchema));
1367+
1368+
const doc = new TestModel({});
1369+
expectType<Types.ObjectId | undefined>(doc.subDocArray[0]._id);
1370+
}

types/inferschematype.d.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import {
1313
DefaultTypeKey,
1414
ObjectIdSchemaDefinition,
1515
IfEquals,
16-
DefaultSchemaOptions
16+
DefaultSchemaOptions,
17+
IsItRecordAndNotAny
1718
} from 'mongoose';
1819

1920
declare module 'mongoose' {
@@ -176,6 +177,30 @@ TypeKey
176177
*/
177178
type PathEnumOrString<T extends SchemaTypeOptions<string>['enum']> = T extends ReadonlyArray<infer E> ? E : T extends { values: any } ? PathEnumOrString<T['values']> : string;
178179

180+
type IsSchemaTypeFromBuiltinClass<T> = T extends (typeof String)
181+
? true
182+
: T extends (typeof Number)
183+
? true
184+
: T extends (typeof Boolean)
185+
? true
186+
: T extends (typeof Buffer)
187+
? true
188+
: T extends (typeof Schema.Types.ObjectId)
189+
? true
190+
: T extends (typeof Schema.Types.UUID)
191+
? true
192+
: T extends (typeof Schema.Types.Decimal128)
193+
? true
194+
: T extends Types.ObjectId
195+
? true
196+
: T extends Types.Decimal128
197+
? true
198+
: T extends Buffer
199+
? true
200+
: T extends (typeof Schema.Types.Mixed)
201+
? true
202+
: IfEquals<T, Schema.Types.ObjectId, true, false>;
203+
179204
/**
180205
* @summary Resolve path type by returning the corresponding type.
181206
* @param {PathValueType} PathValueType Document definition path type.
@@ -189,15 +214,21 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
189214
IfEquals<Item, never, any[], Item extends Schema ?
190215
// If Item is a schema, infer its type.
191216
Types.DocumentArray<InferSchemaType<Item>> :
192-
Item extends Record<TypeKey, any>?
217+
Item extends Record<TypeKey, any> ?
193218
Item[TypeKey] extends Function | String ?
194219
// If Item has a type key that's a string or a callable, it must be a scalar,
195220
// so we can directly obtain its path type.
196221
ObtainDocumentPathType<Item, TypeKey>[] :
197222
// If the type key isn't callable, then this is an array of objects, in which case
198223
// we need to call ObtainDocumentType to correctly infer its type.
199-
ObtainDocumentType<Item, any, { typeKey: TypeKey }>[]:
200-
ObtainDocumentPathType<Item, TypeKey>[]
224+
ObtainDocumentType<Item, any, { typeKey: TypeKey }>[] :
225+
IsSchemaTypeFromBuiltinClass<Item> extends true ?
226+
ObtainDocumentPathType<Item, TypeKey>[] :
227+
IsItRecordAndNotAny<Item> extends true ?
228+
Item extends Record<string, never> ?
229+
ObtainDocumentPathType<Item, TypeKey>[] :
230+
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
231+
ObtainDocumentPathType<Item, TypeKey>[]
201232
>:
202233
PathValueType extends ReadonlyArray<infer Item> ?
203234
IfEquals<Item, never, any[], Item extends Schema ?
@@ -206,7 +237,13 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
206237
Item[TypeKey] extends Function | String ?
207238
ObtainDocumentPathType<Item, TypeKey>[] :
208239
ObtainDocumentType<Item, any, { typeKey: TypeKey }>[]:
209-
ObtainDocumentPathType<Item, TypeKey>[]
240+
IsSchemaTypeFromBuiltinClass<Item> extends true ?
241+
ObtainDocumentPathType<Item, TypeKey>[] :
242+
IsItRecordAndNotAny<Item> extends true ?
243+
Item extends Record<string, never> ?
244+
ObtainDocumentPathType<Item, TypeKey>[] :
245+
Types.DocumentArray<ObtainDocumentType<Item, any, { typeKey: TypeKey }>> :
246+
ObtainDocumentPathType<Item, TypeKey>[]
210247
>:
211248
PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
212249
IfEquals<PathValueType, Schema.Types.String> extends true ? PathEnumOrString<Options['enum']> :

0 commit comments

Comments
 (0)