Documenting generic type works for direct inheritance. But when I have a inheritance chain, there is no way to make it work for the grandchildren class. Here is an example:
* @property {string} color
* @template {T}
*/
class MyColor {
constructor() {
this.color = 'unknown';
}
/**
* @returns {T}
*/
static makeColor() {
return /**@type {T}*/ new this.prototype.constructor();
}
}
/**
* @extends MyColor<Red>
* @template {T}
*/
class Red extends MyColor {
constructor() {
super();
this.color = 'red';
}
}
/**
* @extends Red<DarkRed>
*/
class DarkRed extends Red {
constructor() {
super();
this.level = 2;
}
darker() {
this.level += 1;
}
}
const circle = DarkRed.makeColor();
DarkRed.makeColor
only recognizes the return as Red
, but not DarkRed
. Is there a way to make it work with @template
? Or is there any other way to make it work?
I am using WebStorm as the IDE.
You can use most JSDoc type syntax and any TypeScript syntax, from the most basic like string to the most advanced, like conditional types.
JsDoc is a great tool for documenting code and providing type-safety in your JavaScript project without any additional configuration. Learn what JsDoc is, how it works, the benefits it provides, and how to use it in your project.
From https://github.com/google/closure-compiler/wiki/Generic-Types#inheritance-of-generic-types, @extends MyColor<Red>
'fixes' the template type instead of propagating it to inheriting type. For example, in
/**
* @constructor
* @template T
*/
var A = function() { };
/** @param {T} t */
A.prototype.method = function(t) { };
/**
* @constructor
* @extends {A<string>}
*/
var B = function() { };
/**
* @constructor
*
* @extends {B<number>}
*/
var C = function() { };
var cc =new C();
var bb = new B();
var bm = bb.method("hello");
var cm = cc.method(1);
cc.method(1)
will result in TYPE_MISMATCH: actual parameter 1 of A.prototype.method does not match formal parameter
found : number
required: string
You can try changing your code to
/**
* @property {string} color
* @template {T}
*/
class MyColor {
constructor() {
this.color = 'unknown';
}
/**
* @returns {T}
*/
static makeColor() {
return /**@type {T}*/ new this.prototype.constructor();
}
}
/**
* @extends MyColor<T>
* @template {T}
*/
class Red extends MyColor {
constructor() {
super();
this.color = 'red';
}
}
const circle1 = Red.makeColor();
/**
* @extends Red<DarkRed>
*
*/
class DarkRed extends Red {
constructor() {
super();
this.level = 2;
}
darker() {
this.level += 1;
}
}
const circle = DarkRed.makeColor();
another possible solution is using @return {this}
instead of @template
(works since 2018.2):
class MyColor {
constructor() {
this.color = 'unknown';
}
/**
* @return {this}
*/
static makeColor() {
return new this.prototype.constructor();
}
}
class Red extends MyColor {
constructor() {
super();
this.color = 'red';
}
}
class DarkRed extends Red {
constructor() {
super();
this.level = 2;
}
darker() {
this.level += 1;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With