Skip to content

Commit ff24d86

Browse files
committed
types: add JSONSerialized helper that can convert HydratedDocument to JSON output type
Fix Automattic#14451
1 parent 925327f commit ff24d86

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

test/types/check-types-filename.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const checkFolder = (folder) => {
1818
}
1919
continue;
2020
} else {
21-
console.error('File ' + entry + ' is not having a valid file-extension.\n');
21+
console.error('File ' + entry + ' does not have a valid extension, must be .d.ts or .gitignore.\n');
2222
process.exit(1);
2323
}
2424
}

test/types/schema.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
InferRawDocType,
1111
InferSchemaType,
1212
InsertManyOptions,
13+
JSONSerialized,
1314
ObtainDocumentType,
1415
ObtainSchemaGeneric,
1516
ResolveSchemaOptions,
@@ -1681,3 +1682,28 @@ async function gh14902() {
16811682
expectType<Binary | null | undefined>(doc.image);
16821683
expectType<Binary | null | undefined>(doc.subdoc!.testBuf);
16831684
}
1685+
1686+
async function gh14451() {
1687+
const exampleSchema = new Schema({
1688+
myId: { type: 'ObjectId' },
1689+
myRequiredId: { type: 'ObjectId', required: true },
1690+
subdoc: {
1691+
type: new Schema({
1692+
subdocProp: Date
1693+
})
1694+
}
1695+
// docArr: [{ nums: [Number], times: [Date] }]
1696+
});
1697+
1698+
const Test = model('Test', exampleSchema);
1699+
1700+
type TestJSON = JSONSerialized<InferSchemaType<typeof exampleSchema>>;
1701+
expectType<{
1702+
myId?: string | undefined | null,
1703+
myRequiredId: string,
1704+
subdoc?: {
1705+
subdocProp?: string | undefined | null
1706+
} | null,
1707+
// docArr: { nums: number[], times: string[] }[]
1708+
}>({} as TestJSON);
1709+
}

types/index.d.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,50 @@ declare module 'mongoose' {
718718
: BufferToBinary<T[K]>;
719719
} : T;
720720

721+
export type ObjectIdToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
722+
[K in keyof T]: T[K] extends mongodb.ObjectId
723+
? string
724+
: T[K] extends (mongodb.ObjectId | null | undefined)
725+
? string | null | undefined
726+
: T[K] extends Types.DocumentArray<infer ItemType>
727+
? Types.DocumentArray<ObjectIdToString<ItemType>>
728+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
729+
? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
730+
: ObjectIdToString<T[K]>;
731+
} : T;
732+
733+
export type DateToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
734+
[K in keyof T]: T[K] extends NativeDate
735+
? string
736+
: T[K] extends (NativeDate | null | undefined)
737+
? string | null | undefined
738+
: T[K] extends Types.DocumentArray<infer ItemType>
739+
? Types.DocumentArray<DateToString<ItemType>>
740+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
741+
? HydratedSingleSubdocument<DateToString<SubdocType>>
742+
: DateToString<T[K]>;
743+
} : T;
744+
745+
export type SubdocsToPOJOs<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
746+
[K in keyof T]: T[K] extends NativeDate
747+
? string
748+
: T[K] extends (NativeDate | null | undefined)
749+
? string | null | undefined
750+
: T[K] extends Types.DocumentArray<infer ItemType>
751+
? ItemType
752+
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
753+
? SubdocType
754+
: SubdocsToPOJOs<T[K]>;
755+
} : T;
756+
757+
export type JSONSerialized<T> = SubdocsToPOJOs<
758+
FlattenMaps<
759+
ObjectIdToString<
760+
DateToString<T>
761+
>
762+
>
763+
>;
764+
721765
/**
722766
* Separate type is needed for properties of union type (for example, Types.DocumentArray | undefined) to apply conditional check to each member of it
723767
* https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types

0 commit comments

Comments
 (0)