Search code examples
node.jstypescriptjsdoc

How to define @template types for parent class in child class?


I am using JSDoc to try and emulate some type hinting and I am running into an issue while trying to get generic types working with @template.

Here is a snippet of the parent class (BaseFixture):

/**
 * @template TSchema
 * @template TRawDoc
 */
export default class {
    /**
     * @param {mongodb.OptionalUnlessRequiredId<TSchema>} record
     * @returns {Promise<*>}
     */
    static async insertOne(record) {
        const recordToInsert = { ...record };
        const res = await this.model.collection.insertOne(recordToInsert);

        return { _id: res.insertedId, ...recordToInsert };
    }
}

And in the child class (ActionLog) I do something like:

/**
 * @template {{test:string}} TSchema
 */
export default class extends BaseFixture {
}

When I go to use code like so:

ActionLog.insertOne({})

Within the auto complete I only get the _id field coming from only the MongoDB type interfaces even though MongoDB type interfaces do support adding a doc type into them.

I can only get it to work when I change my JSDoc to:

@param {mongodb.OptionalUnlessRequiredId<{test:string}>} record

At which point test property correctly shows up as string in my auto complete.

I sense I must be doing something really basic wrong but I have searched a lot on this and I cannot seem to work it out.

How can I defined generic types in inheritance?


Solution

  • Use @extends in the derived class's documentation to pass generic types to the parent. Here's a simplified example:

    /**
     * @template T
     */
    class Foo {
    
      /**
       * @param {T} input
       */
      insert(input) {}
    }
    
    /**
     * @extends Foo<string>
     */
    class DerivedFoo extends Foo {}
    
    new DerivedFoo().insert(input) // input: string
    

    Playground