Reputation: 13
I've recently found out that you can implement JSDoc generics within VSCode for a javascript project, which is fantastic. A big issue I've had with writing JS in the past is having the intellisense never really knowing which types I'm dealing with.
I followed this documentation on how to implement generics (using the @template annotation): https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#template
It works mostly as in I can properly see my class type. The problem is that it doesn't actually seem to know about any of the non-static methods and properties.
Here's some example code:
"use strict";
class Parent {
age = 10;
outputAge() {
console.log(`My age is ${this.age}`);
}
}
class Child extends Parent {
name = "Bob";
outputName() {
console.log(`My name is ${this.name}`);
}
}
/**
* @template T
* @param {T} classType
* @returns {T}
*/
function genericFunction(classType) {
return new classType();
}
const testGeneric = genericFunction(Child);
testGeneric.outputName();
testGeneric.outputAge();
The code executes properly. testGeneric
correctly has the outputAge()
and outputName()
methods at runtime.
The problem is that VSCode doesn't seem to know about:
age
name
outputAge()
outputName()
I suspect this is because the way the generics work. It's seemingly knowing it's a type Child
, but not that it's an instance of Child
. If I added any static methods, they'd correctly show up in the intellisense.
If I inline annotate testGeneric
to have a type of Child
, I can see all the properties and methods:
My question to you all: Is there a way to correctly setup my template to know it returns an instance of T
or is this just a limitation/bug in VSCode's intellisense?
Let me know if anything needs clarification.
Upvotes: 1
Views: 741
Reputation: 26307
Since I couldn't find anything equivalent to ReturnType
for JSDoc, I've decided to do the other way, and make the parameter return T
, so that @returns {T}
now returns the instance type:
/**
* @template T
* @param {{ new(...args: any[]): T }} classType
* @returns {T}
*/
function genericFunction(classType) {
return new classType();
}
Tested with https://vscode.dev/ and typescriptlang.org/play
Upvotes: 1
Reputation: 641
If you want to use @template, then it seems to me that it would be more correct
/**
* @template ParentType
* @property {number} age
* @property {function(): void} outputAge
*/
class Parent {
age = 10;
outputAge() {
console.log(`My age is ${this.age}`);
}
}
/**
* @template ChildType
* @extends {Parent}
* @property {string} name
* @property {function(): void} outputName
*/
class Child extends Parent {
name = "Bob";
outputName() {
console.log(`My name is ${this.name}`);
}
}
/**
* @template {ChildType} T
* @param {T} classType
* @returns {T}
*/
function genericFunction(classType) {
return new classType();
}
const testGeneric = genericFunction(Child);
testGeneric.outputName();
testGeneric.outputAge();
Upvotes: 0