I have a base class (Validator
) that is extended by a child class (ValidatorRequired
).
Then in another class I want to have a collection of instances that may be of base class type (Validator
) or any of its descendants (ValidatorRequired
).
However, when I try to create an instance of a child class and place it inside that collection (at FormField
class constructor), I get a weak warning from PhpStorm: Assigned expression type ValidatorRequired is not assignable to type Validator
:
I suspect the error comes from the fact I've not defined the @type
tag correctly.
What is the correct way to fix that inspection?
FormField.js
:
import { ValidatorRequired } from './ValidatorRequired';
export class FormField {
/**
* Field's current value.
*
* @type {number|string}
*/
value;
/**
* A collection of validators that should be run each time the field is validated.
*
* @type {Object.<string, Validator>}
*/
validators = {};
constructor({ required }) {
this.required = Boolean(required);
// The part after the `=` operator is underlined with grey as a weak warning
this.validators.validatorRequired = new ValidatorRequired({ formField: this });
}
}
Validator.js
:
export class Validator {
/**
* The field to validate.
*
* @type {FormField}
*/
formField;
/**
* @param formField {FormField}
*/
constructor({ formField }) {
this.formField = formField;
}
/**
* Validates a field.
* Should be overridden by child classes.
*
* @returns {boolean}
*/
validate() {
return this.success();
}
/**
* Ends validation with successful result.
*
* @returns {boolean}
*/
success() {
return true;
}
/**
* Ends validation with an error.
*
* @returns {boolean}
*/
error() {
return false;
}
}
ValidatorRequired.js
:
import { Validator } from './Validator';
/**
* A validator that checks for field's value to be non-empty when it is required.
*/
export class ValidatorRequired extends Validator {
/**
* Validates a field.
*
* @returns {boolean}
*/
validate() {
// If the field is not required, return success.
if (!this.formField.required) {
return this.success();
}
// If the value is not falsy, return success.
if (this.formField.value) {
return this.success();
}
// If all previous checks have failed, return error.
return this.error();
}
}
Turns out the error was not in the @type
tag in JSDoc, rather in how PhpStorm treats the class that is specified there.
I have React library imported somewhere else in my project. And React has a class Validator
defined. PhpStorm is aware of that and thinks the Validator
I specified in JSDoc is the Validator
in React and not my own Validator
.
This fact is proved when you try going to the definition of class Validator
through JSDoc comment for validators
field (Ctrl + click on the class, or place a cursor at the class and press Ctrl+B). If you do that, you get a "Choose Declaration" dialogue window, where all the possible declarations are listed:
So the solution is to make PhpStorm think the Validator
specified is 100% my own class. This is easily done by explicitly importing the Validator
:
FormField.js
:
import { Validator } from './Validator';
This solution has a minor downside: your base class (Validator
) will be included in the bundle regardless of whether it is used or not. However, I think this has a negligible impact, because:
ValidatorRequired
extends Validator
).@type
tag (class FormField
), you are probably using them in the descendants of the class that is documenting the usage (FormField
descendants), or you are doing something wrong.