Skip to content

Instantly share code, notes, and snippets.

@ospatil
Created March 31, 2021 14:33
Show Gist options
  • Save ospatil/30dfd93d6632505e431fd894f552772f to your computer and use it in GitHub Desktop.
Save ospatil/30dfd93d6632505e431fd894f552772f to your computer and use it in GitHub Desktop.
TypeScript type LeanDocument for mongoose and nestjs
class Doc {
attrA: string;
attrB: string;
id: string;
_id: any;
_v: number;
func1 = () => {}
func2 = () => {}
}
class MyDocument extends Doc {
attrC: string;
attrD: string;
_id: string;
}
type LeanDocument<C, P extends {_id: unknown}> = Pick<C, Exclude<keyof C, keyof P>> & Pick<P, Extract<keyof P, "id" | "_v">> & {
_id: C extends { _id: unknown } ? C['_id'] : P['_id'];
};
const myDoc:MyDocument = new MyDocument();
// try typing myDoc. and see that all properties from MyDocument and Doc are available
// myDoc.
const leanDoc:LeanDocument<MyDocument, Doc> = myDoc;
// Now try typing excluded. The only proerties available are attrC, attrD, id, _id and _v
// leanDoc.
import { Model, Document } from 'mongoose';
export type LeanDocument<C extends Document, P extends Document> = Pick<
C, // pick keys from C i.e. User provided document object
Exclude<keyof C, keyof P> // Remove all attributes and methods coming from Document
> &
Pick<P, Extract<keyof P, 'id' | '_v'>> & {
// Above: extract and pick id (which is a virtual prop) & _v from Document
_id: C extends { _id: unknown } ? C['_id'] : P['_id']; // Use user-provided custom _id if available
};
//...
//...
export abstract class BaseService<T extends Document> {
constructor(protected readonly _model: Model<T>) {}
protected toObject(doc: T): object {
return doc.toObject({ virtuals: true, getters: true });
}
async findAll(query): Promise<LeanDocument<T, Document>[]> {
return this.findDocuments(query).then((docs) =>
docs.map(this.toObject.bind(this))
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment