Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: correctly handle union types in BufferToBinary and related helpers #15103

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions test/types/lean.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,34 @@ async function gh13382() {
const res = await Test.updateOne({}, { name: 'bar' }).lean();
expectAssignable<{ matchedCount: number, modifiedCount: number }>(res);
}

async function gh15057() {
type Attachment =
| {
type: 'foo';
value?: undefined;
}
| {
type: 'string';
value?: string;
};

const TestSchema = new Schema<Attachment>({
type: { type: String, required: true },
value: { type: String }
});

const AttachmentModel = model<Attachment>('test', TestSchema);

const main = async() => {
const item = await AttachmentModel.findOne().lean();

if (!item) return;

doSomeThing(item);
};

const doSomeThing = (item: Attachment) => {
console.log(item);
};
}
104 changes: 55 additions & 49 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,76 +712,82 @@ declare module 'mongoose' {
/**
* Converts any Buffer properties into mongodb.Binary instances, which is what `lean()` returns
*/
export type BufferToBinary<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
[K in keyof T]: T[K] extends Buffer
? mongodb.Binary
: T[K] extends (Buffer | null | undefined)
? mongodb.Binary | null | undefined
: T[K] extends Types.DocumentArray<infer ItemType>
export type BufferToBinary<T> = T extends Buffer
? mongodb.Binary
: T extends TreatAsPrimitives
? T
: T extends Record<string, any> ? {
[K in keyof T]: T[K] extends Buffer
? mongodb.Binary
: 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;
} : T;

/**
* Converts any Buffer properties into { type: 'buffer', data: [1, 2, 3] } format for JSON serialization
*/
export type BufferToJSON<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
[K in keyof T]: T[K] extends Buffer
? { type: 'buffer', data: number[] }
: 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]>;
} : T;
export type BufferToJSON<T> = T extends Buffer
? { type: 'buffer', data: number[] }
: T extends TreatAsPrimitives
? T
: T extends Record<string, any> ? {
[K in keyof T]: T[K] extends Buffer
? { type: 'buffer', data: number[] }
: 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;

/**
* Converts any ObjectId properties into strings for JSON serialization
*/
export type ObjectIdToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
[K in keyof T]: T[K] extends mongodb.ObjectId
? string
: T[K] extends (mongodb.ObjectId | null | undefined)
? 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;
export type ObjectIdToString<T> = T extends mongodb.ObjectId
? string
: T extends TreatAsPrimitives
? T
: T extends Record<string, any> ? {
[K in keyof T]: T[K] extends mongodb.ObjectId
? string
: 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;

/**
* Converts any Date properties into strings for JSON serialization
*/
export type DateToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
[K in keyof T]: T[K] extends NativeDate
? string
: T[K] extends (NativeDate | null | undefined)
? 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;
export type DateToString<T> = T extends NativeDate
? string
: T extends TreatAsPrimitives
? T
: T extends Record<string, any> ? {
[K in keyof T]: T[K] extends NativeDate
? string
: T[K] extends (NativeDate | null | undefined)
? 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;

/**
* Converts any Mongoose subdocuments (single nested or doc arrays) into POJO equivalents
*/
export type SubdocsToPOJOs<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
[K in keyof T]: T[K] extends NativeDate
? string
: 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]>;
[K in keyof T]: T[K] extends Types.DocumentArray<infer ItemType>
? ItemType[]
: T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
? SubdocType
: SubdocsToPOJOs<T[K]>;
} : T;

export type JSONSerialized<T> = SubdocsToPOJOs<
Expand Down
Loading