francescov1 / mongoose-tsgen

A plug-n-play Typescript generator for Mongoose.
105 stars 24 forks source link

Strongly typed method parameters and return types #137

Closed LucasRomier closed 8 months ago

LucasRomier commented 8 months ago

Hi,

To start off, I am very fond of this extension as it has saved me countless hours of defining my Mongoose Schemas.

Would it however be possible to strongly type the parameters of my schema methods?

E.g., my method is getAccessLog(pageSize: number, page: number, sort: "date" | "type" | "value", sortOrder: -1 | 1): Prom Currently results in the following under the generated method types getAccessLog: (this: IPlanDocument, ...args: any[]) => any;

Would it be possible, to stronly type this to getAccessLog: (this: IPlanDocument, pageSize: number, page: number, sort: "date" | "type" | "value", sortOrder: -1 | 1) => ILog[];

Thank you for your consideration!

francescov1 commented 8 months ago

Hi @LucasRomier,

Glad to hear its useful! Exactly why I built it for myself.

The tool does its best to determine the type of mongoose methods and generate them strongly, but sometimes it cant determine them (eg they are in a format that is not recognized). If you can paste your full schema and method definition, I can do some testing and see whats preventing it from picking the type up properly and try to add support for it.

LucasRomier commented 8 months ago

Yes of course, I created a pastebin for you: https://pastebin.com/6yxuPRsR.

In it, I detailed the three additions that I would love to have:

Thank you for your consideration!

Best regards

francescov1 commented 8 months ago

Sorry for the delay @LucasRomier, planning to look at this over the weekend. Thanks for providing these details!

francescov1 commented 8 months ago

Hi @LucasRomier, I was able to find the problem. Finding types in a file can be a bit tricky due to the variety of ways that TS can be defined. I was able to get your file to generate proper types by making the following changes:

Lastly, if you aren't already, make sure you use the imports CLI argument (or option in mtgen.config.json): --imports "import { Moment } from \"moment-timezone\"". This will ensure that moment-timezone is imported into the generated type file so that the virtual return type works properly. Usually with import statements its easier to use the mtgen.config.json file, you can see an example in the README.

Here's the resulting file:

import { Schema, model } from "mongoose";
import { IPlanModel, IPlanSchema, IPlanDocument} from "../types/mongoose-types";
import moment, { Moment } from "moment-timezone";
import { pbkdf2, randomBytes } from "crypto";

const PlanSchema: IPlanSchema = new Schema({
    expiresOnRaw: {
        type: Date,
        default: undefined
    },
    secret: {
        key: {
            type: String,
            unique: true,
            default: () => randomBytes(64).toString("hex"),
            required: [true, 'Secret must be set'],
        },
        lastKeyChange: {
            type: Date
        }
    },
}, {
    timestamps: true
});

PlanSchema.methods = {
  newKey(key: string): Promise<void> {
    const promise = new Promise<void>(async (resolve, reject) => {
        this.secret.key = await Plan.hashKey(key);
        this.secret.lastKeyChange = new Date();

        try {
            await this.save();
        } catch (err) {
            return reject(err);
        }

        return resolve();
    });

    return promise;
  }
}

PlanSchema.statics = {
  hashKey(key: string): Promise<string> {
    const promise = new Promise<string>((resolve, reject) => {
        pbkdf2(key, "12345", 1, 1, "sha256", async (err, hashed) => {
            if (err) return reject(err);

            resolve(hashed.toString("hex"));
        });
    });
    return promise;
  }
}

PlanSchema.virtual("expiresOn").get(function(): Moment | undefined {
    if (!this.expiresOnRaw) return undefined;

    return moment(this.expiresOnRaw);
});

const Plan: IPlanModel = model<IPlanDocument, IPlanModel>("IPlan", PlanSchema);
export default Plan;
LucasRomier commented 8 months ago

Hi @francescov1,

This is perfect, thank you so much! Already found three errors where I used Number instead of number 😅...

Best regards!

francescov1 commented 8 months ago

Type safe mongoose is a game changer 🙌 happy to help!