JSDoc: универсальный тип документа, который работает для классов внуков - PullRequest
0 голосов
/ 28 июня 2018

Документирование родовых типов работ для прямого наследования. Но когда у меня есть цепочка наследования, я не могу заставить ее работать для класса внуков. Вот пример:

 * @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 распознает только возврат как Red, но не DarkRed. Есть ли способ заставить его работать с @template? Или есть другой способ заставить его работать?

Я использую WebStorm в качестве IDE.

1 Ответ

0 голосов
/ 28 июня 2018

С https://github.com/google/closure-compiler/wiki/Generic-Types#inheritance-of-generic-types, @extends MyColor<Red> «исправляет» тип шаблона, а не распространяет его на наследуемый тип. Например, в

/**
 * @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) приведет к TYPE_MISMATCH: actual parameter 1 of A.prototype.method does not match formal parameter found : number required: string

Вы можете попробовать изменить свой код на

/**
* @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();

другое возможное решение - использовать @return {this} вместо @template (работает с 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;
  }
}
...