0

I am attempting to annotate all my JavaScript functions and class properties with JSDoc to enable proper type checking using TypeScript and the checkJS option.

However, since I want to support older browsers (IE9), and I do not want to transpile the code using Babel, I need to use ES5-era JavaScript and cannot use "class" to define a class. Therefore, I need to resort to plain old function prototypes.

In the project I'm working on, I have the following class:

/**
 * A condition class, executes a set function on results that meet their required conditions.
 * @class
 * @template T
 */
function Condition()
{
  /** @type {{condition?: boolean, result: T}[]} A list of conditions to execute. */
  this.list = new Array();
}

/** 
 * Adds a condition
 * @param {{condition: boolean, result: T}} condition The object with the condition and the result to be sent to the executing function.
 */
Condition.prototype.add = function(condition)
{
  this.list.push(condition);
}

/**
 * Executes the added conditions.
 * @param {function(T):void} action The function to be executed when a condition is true.
 */
Condition.prototype.execute = function(action)
{
  this.list.forEach(function(condition) { if(condition.condition) action(condition.result); });
}

In this class, the result element is always of the same type within the same class instance, making this a perfect use case of a template, as can be seen in the code.

However, when I attempt to use the class using, for example, the following code:

var conditionList = /**@type {Condition<string>} */(new Condition());
conditionList.add({ condition: true, result: 'yes' });
conditionList.execute(function(value) { console.log(value); });

I get the following error in VSCode:

Type 'string' is not assignable to type 'T'. The expected type comes from property 'result' which is declared here on type '{ condition: boolean; result: T; }'

When I hover the mouse on conditionList, the popup says: var conditionList: typeof Condition.

Changing the conditionList declaration to var /**@type {typeof Condition<string>} */(new Condition()); also does not work, and throws an error saying that typeof Condition cannot be converted to typeof Condition.

Therefore I have no idea on what to do in order to allow the template to work, while keeping the ES5 class declaration style.

However, if i convert the code to an ES6-style class (class Condition), and I keep the annotations just as they are, then the code works properly. In that case, hovering over conditionList results in a popup saying var conditionList: Condition<string> and there are no errors.

Is there any way to get the same behavior using the ES5 style classes? Am I missing something? Or might this be something unimplemented in VSCode's TypeScript checker?

  • Looks like `@template` is not officially supported. I guess here could be some implementation bugs in IDEs regarding this tag. – Lesha Ogonkov Nov 17 '18 at 07:14
  • I'm guessing it's a bug then. Incidentally, the template expression `T` is recognized in the prototype functions of `Condition`, even though `Condition` itself does not use the template when instantiated. Also, prototype functions cannot have their own templates, which leads me to believe the `@template` implementation is unfinished. – José Cadete Nov 17 '18 at 09:55

1 Answers1

0

It seems to be a bug, and has an open issue in Github. It seems it will not be fixed until TypeScript 3.3 is out unfortunately:

https://github.com/Microsoft/TypeScript/issues/26883