# valid-types * [Options](#user-content-valid-types-options) * [`allowEmptyNamepaths`](#user-content-valid-types-options-allowemptynamepaths) * [Context and settings](#user-content-valid-types-context-and-settings) * [Failing examples](#user-content-valid-types-failing-examples) * [Passing examples](#user-content-valid-types-passing-examples) Requires all types/namepaths to be valid JSDoc, Closure compiler, or TypeScript types (configured by `settings.jsdoc.mode`). Note that what determines a valid type is handled by our type parsing engine, [jsdoc-type-pratt-parser](https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser), using [`settings.jsdoc.mode`](#user-content-eslint-plugin-jsdoc-settings-mode) to determine whether to use jsdoc-type-pratt-parser's "permissive" parsing or the stricter "jsdoc", "typescript", "closure" modes. The following tags have their "type" portions (the segment within brackets) checked (though those portions may sometimes be confined to namepaths, e.g., `@modifies`): 1. Tags with required types: `@type`, `@implements` 1. Tags with required types in Closure or TypeScript: `@this`, `@define` (Closure only) 1. Tags with optional types: `@enum`, `@member` (`@var`), `@typedef`, `@augments` (or `@extends`), `@class` (or `@constructor`), `@constant` (or `@const`), `@module` (module paths are not planned for TypeScript), `@namespace`, `@throws`, `@exception`, `@yields` (or `@yield`), `@modifies` (undocumented jsdoc); `@param` (`@arg`, `@argument`), `@property` (`@prop`), and `@returns` (`@return`) also fall into this category, but while this rule will check their type validity, we leave the requiring of the type portion to the rules `require-param-type`, `require-property-type`, and `require-returns-type`, respectively. 1. Tags with types that are available optionally in Closure: `@export`, `@package`, `@private`, `@protected`, `@public`, `@static`; `@template` (TypeScript also) 1. Tags with optional types that may take free text instead: `@throws` The following tags have their name/namepath portion (the non-whitespace text after the tag name) checked: 1. Name(path)-defining tags requiring namepath: `@event`, `@callback`, `@exports` (JSDoc only), `@external`, `@host`, `@name`, `@typedef` (JSDoc only), and `@template` (TypeScript/Closure only); `@param` (`@arg`, `@argument`) and `@property` (`@prop`) also fall into this category, but while this rule will check their namepath validity, we leave the requiring of the name portion to the rules `require-param-name` and `require-property-name`, respectively. 1. Name(path)-defining tags (which may have value without namepath or their namepath can be expressed elsewhere on the block): `@class`, `@constructor`, `@constant`, `@const`, `@function`, `@func`, `@method`, `@interface` (non-Closure only), `@member`, `@var`, `@mixin`, `@namespace`, `@module` (module paths are not planned for TypeScript) 1. Name(path)-pointing tags requiring namepath: `@alias`, `@augments`, `@extends` (JSDoc only), `@lends`, `@memberof`, `@memberof!`, `@mixes`, `@requires`, `@this` (JSDoc only) 1. Name(path)-pointing tags (which may have value without namepath or their namepath can be expressed elsewhere on the block): `@listens`, `@fires`, `@emits`. 1. Name(path)-pointing tags which may have free text or a namepath: `@see` 1. Name(path)-pointing tags (multiple names in one): `@borrows` ...with the following applying to the above sets: - Expect tags in set 1-4 to have a valid namepath if present - Prevent sets 2 and 4 from being empty by setting `allowEmptyNamepaths` to `false` as these tags might have some indicative value without a path or may allow a name expressed elsewhere on the block (but sets 1 and 3 will always fail if empty) - For the special case of set 6, i.e., `@borrows as `, check that both namepaths are present and valid and ensure there is an `as ` between them. In the case of ``, it can be preceded by one of the name path operators, `#`, `.`, or `~`. - For the special case of `@memberof` and `@memberof!` (part of set 3), as per the [specification](https://jsdoc.app/tags-memberof.html), they also allow `#`, `.`, or `~` at the end (which is not allowed at the end of normal paths). If you define your own tags, `settings.jsdoc.structuredTags` will allow these custom tags to be checked, with the name portion of tags checked for valid namepaths (based on the tag's `name` value), their type portions checked for valid types (based on the tag's `type` value), and either portion checked for presence (based on `false` `name` or `type` values or their `required` value). See the setting for more details. ## Options A single options object has the following properties. ### allowEmptyNamepaths Set to `false` to bulk disallow empty name paths with namepath groups 2 and 4 (these might often be expected to have an accompanying name path, though they have some indicative value without one; these may also allow names to be defined in another manner elsewhere in the block); you can use `settings.jsdoc.structuredTags` with the `required` key set to "name" if you wish to require name paths on a tag-by-tag basis. Defaults to `true`. ## Context and settings ||| |---|---| |Context|everywhere| |Tags|For name only unless otherwise stated: `alias`, `augments`, `borrows`, `callback`, `class` (for name and type), `constant` (for name and type), `enum` (for type), `event`, `external`, `fires`, `function`, `implements` (for type), `interface`, `lends`, `listens`, `member` (for name and type), `memberof`, `memberof!`, `mixes`, `mixin`, `modifies`, `module` (for name and type), `name`, `namespace` (for name and type), `param` (for name and type), `property` (for name and type), `returns` (for type), `see` (optionally for name), `this`, `throws` (for type), `type` (for type), `typedef` (for name and type), `yields` (for type)| |Aliases|`extends`, `constructor`, `const`, `host`, `emits`, `func`, `method`, `var`, `arg`, `argument`, `prop`, `return`, `exception`, `yield`| |Closure-only|For type only: `package`, `private`, `protected`, `public`, `static`| |Recommended|true| |Options|`allowEmptyNamepaths`| |Settings|`mode`, `structuredTags`| ## Failing examples The following patterns are considered problems: ````ts /** * @param {Array): !Array} */ parseArray = function(parser) { return function(array) { return array.map(parser); }; }; // Settings: {"jsdoc":{"mode":"closure"}} // Message: Syntax error in namepath: T<~, R /** * @template T, R<~ * @param {function(!T): !R} parser * @return {function(!Array): !Array} */ parseArray = function(parser) { return function(array) { return array.map(parser); }; }; // Settings: {"jsdoc":{"mode":"closure"}} // Message: Syntax error in namepath: R<~ /** * @template T, R<~ * @param {function(!T): !R} parser * @return {function(!Array): !Array} */ parseArray = function(parser) { return function(array) { return array.map(parser); }; }; // Settings: {"jsdoc":{"mode":"closure"}} // Message: Syntax error in namepath: R<~ /** * @suppress */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} // Message: Tag @suppress must have a type in "closure" mode. /** * @suppress {visibility} sth */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} // Message: @suppress should not have a name in "closure" mode. /** * @suppress {visibility|blah} */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} // Message: Syntax error in suppress type: blah /** * @param {Object[]} employees * @param {string} employees[.name - The name of an employee. */ function quux () {} // Message: Invalid name: unpaired brackets /** * @param {Object[]} employees * @param {string} [] - The name of an employee. */ function quux () {} // Message: Invalid name: empty name /** * @param {string} [name=] - The name of an employee. */ function quux () {} // Message: Invalid name: empty default value /** * @param {string} [name==] - The name of an employee. */ function quux () {} // Message: Invalid name: invalid default value syntax /** * @type {{message: string?}} */ function quux (items) { } // Settings: {"jsdoc":{"mode":"closure"}} // Message: Syntax error in type: JsdocTypeNullable /** * @type {[message: string?]} */ function quux (items) { } // Settings: {"jsdoc":{"mode":"typescript"}} // Message: Syntax error in type: JsdocTypeNullable /** * An inline {@link} tag without content. */ // Message: Inline tag "link" missing content /** * An inline {@tutorial} tag without content. */ // Message: Inline tag "tutorial" missing content /** * @param {SomeType} aName An inline {@link} tag without content. */ // Message: Inline tag "link" missing content /** * With reserved word in type * @param {Array} foo */ function quux() { } // Message: Syntax error in type: Array ```` ## Passing examples The following patterns are not considered problems: ````ts /** * @param {Array} foo */ function quux() { } /** * @param {string} foo */ function quux() { } /** * @param foo */ function quux() { } /** * @borrows foo as bar */ function quux() { } /** * @borrows foo as #bar */ function quux() { } /** * @see foo% */ function quux() { } /** * @alias module:namespace.SomeClass#event:ext_anevent */ function quux() { } /** * @callback foo */ function quux() { } /** * @callback */ function quux() { } // "jsdoc/valid-types": ["error"|"warn", {"allowEmptyNamepaths":true}] /** * @class */ function quux() { } /** * @see {@link foo} */ function quux() { } // Settings: {"jsdoc":{"structuredTags":{"see":{"name":"namepath-referencing","required":["name"]}}}} /** * * @fires module:namespace.SomeClass#event:ext_anevent */ function quux() { } /** * @memberof module:namespace.SomeClass~ */ function quux() { } /** * @memberof! module:namespace.SomeClass. */ function quux() { } /** * */ function quux() { } /** * @aCustomTag */ function quux() { } /** * @constant {string} */ const FOO = 'foo'; /** * @constant {string} FOO */ const FOO = 'foo'; /** * @extends Foo */ class Bar {}; /** * @extends Foo */ class Bar {}; /** * @extends {Foo} */ class Bar {}; // Settings: {"jsdoc":{"mode":"closure"}} /** * @typedef {number | string} UserDefinedType */ /** * @typedef {number | string} */ let UserDefinedGCCType; // Settings: {"jsdoc":{"mode":"closure"}} /** * @modifies {foo | bar} */ function quux (foo, bar, baz) {} /** * @this {Navigator} */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} /** * @export {SomeType} */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} /** * @define {boolean} */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} /** * @define */ function quux () {} /** * Foo function. * * @interface foo */ function foo(bar) {} // Settings: {"jsdoc":{"mode":"typescript"}} /** * Foo function. * * @param {[number, string]} bar - The bar array. */ function foo(bar) {} // Settings: {"jsdoc":{"mode":"typescript"}} /** * Foo function. * * @param {[number, string]} bar - The bar array. */ function foo(bar) {} /** * Foo function. * * @param {[number, string]} bar - The bar array. */ function foo(bar) {} // Settings: {"jsdoc":{"mode":"permissive"}} /** * @typedef {SomeType} */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} // "jsdoc/valid-types": ["error"|"warn", {"allowEmptyNamepaths":false}] /** * @private {SomeType} */ function quux () {} // Settings: {"jsdoc":{"mode":"closure"}} /** * @param */ function quux() { } // "jsdoc/valid-types": ["error"|"warn", {"allowEmptyNamepaths":false}] /** * @see */ function quux() { } // Settings: {"jsdoc":{"structuredTags":{"see":{"name":"namepath-referencing"}}}} /** * @template T, R * @param {function(!T): !R} parser * @return {function(!Array): !Array} */ parseArray = function(parser) { return function(array) { return array.map(parser); }; }; // Settings: {"jsdoc":{"mode":"closure"}} /** * @template T, R<~ * @param {function(!T): !R} parser * @return {function(!Array): !Array} */ parseArray = function(parser) { return function(array) { return array.map(parser); }; }; // Settings: {"jsdoc":{"mode":"jsdoc"}} /** * @template {string} K - K must be a string or string literal * @template {{ serious: string }} Seriousalizable - must have a serious property * @param {K} key * @param {Seriousalizable} object */ function seriousalize(key, object) { // ???? } // Settings: {"jsdoc":{"mode":"typescript"}} /** * @module foo/bar */ /** * @module module:foo/bar */ /** * @template invalid namepath,T Description */ function f() {} // Settings: {"jsdoc":{"mode":"closure"}} /** * Description of complicated type. * * @template T Description of the T type parameter. * @template U - Like other tags, this can have an optional hyphen before the description. * @template V,W More parameters * @template W,X - Also with a hyphen */ type ComplicatedType = never /** Multi-line typedef for an options object type. * * @typedef {{ * prop: number * }} MyOptions */ /** * @extends {SomeType} */ class quux {} // Settings: {"jsdoc":{"mode":"typescript"}} /** * @suppress {visibility|underscore} */ function quux() { } // Settings: {"jsdoc":{"mode":"closure"}} /** * @param {string} id * @param {Object} options * @param {boolean} options.isSet * @param {string} options.module */ function quux ( id, options ) { } /** * Assign the project to a list of employees. * @param {Object[]} employees - The employees who are responsible for the project. * @param {string} employees[].name - The name of an employee. * @param {string} employees[].department - The employee's department. */ function assign(employees) { // ... } // "jsdoc/valid-types": ["error"|"warn", {"allowEmptyNamepaths":true}] /** * @param {typeof obj["level1"]["level2"]} foo * @param {Parameters[0]} ghi * @param {{[key: string]: string}} hjk */ function quux() { } // Settings: {"jsdoc":{"mode":"typescript"}} /** * @returns {Promise<{publicKey, privateKey}>} - The public and private key */ /** * Some other {@inline} tag. */ /** * @param {SomeType} aName An inline {@link text} tag with content. */ /** * An inline {@link text} tag with content. */ /** * @param typeof * @param readonly * @param import * @param is */ function quux() { } /** * @import { TestOne, TestTwo } from "./types" */ /** * @returns {@link SomeType} */ /** * @template {string} Selector * @template {keyof GlobalEventHandlersEventMap} TEventType * @template {Element} [TElement=import('typed-query-selector/parser').ParseSelector] * @param {Selector} selector * @param {TEventType} type * @param {import('delegate-it').DelegateEventHandler} callback * @param {Omit} [options] * @returns {void} */ export function onGlobalEvent (selector, type, callback, options) { delegate(document, selector, type, callback, options) } /** * Even if added to `structuredTags` as in our recommended config, * we don't want `valid-types` to report since * `jsdoc/require-next-type` already does this. * @next */ function a () {} // Settings: {"jsdoc":{"structuredTags":{"next":{"required":["type"]}}}} /** * With reserved word in name * @typedef {SomeType} import */ /** * With reserved word in namepath * @param {SomeType} import */ /** * @param readonly */ /** * @param {boolean} readonly */ /** * @param {object} params * @param {boolean} params.readonly */ /** * An object interface * @typedef {Object} FooBar * @property {boolean} readonly * @property {boolean} private * @property {boolean} public * @property {boolean} constant */ /** * @param {object} props * @param {string} props.is */ class Test { /** * @returns {this} */ method() { return this; } } /** * @typedef {Object} module:src/core/Player~mediaFormat */ // Settings: {"jsdoc":{"mode":"jsdoc"}} let SettingName = /** @type {const} */ ({ THEME: `theme`, }) /** * @typedef {Array} AnnotatedCharacter * @property {string} 0 Character data * @property {string[]} 1 Annotation hashses */ // Settings: {"jsdoc":{"mode":"jsdoc"}} /** Some annoying set of bitmasks or something. * * @property {number} [BITMASK_VALUE_A=16] - blah blah * @property {number} BITMASK_VALUE_B=32 - the other thing */ const MY_BITMASK_CONSTANT = { BITMASK_VALUE_A: 1 << 4, BITMASK_VALUE_B: somePrivateVariableHere }; /** * @template [T=Record] */ function quux () {} ````