Search code examples
typescriptjsdoctypescript-eslinteslint-plugin-jsdoc

How do I configure ESLint to check for TypeScript class property JSDoc comments?


I have a TypeScript application (4.0.x) that includes the following packages:

"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"@vue/cli-plugin-eslint": "^4.5.4",
"eslint": "^7.8.1",
"eslint-plugin-jsdoc": "^30.3.1",

My .eslintrc.js includes the following:

'extends': [
    'plugin:vue/essential',
    'eslint:recommended',
    '@vue/typescript/recommended',
    "plugin:jsdoc/recommended"
],
parserOptions: {
    ecmaVersion: 2020
},
plugins: [
    "jsdoc"
],
rules: {
    'jsdoc/require-property-description': 1,
    'jsdoc/require-description': 1,
    'jsdoc/require-param-type': 'off',
    'jsdoc/require-returns-type': 'off',
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}

When I run ESLint against my code I want it to return an error or warning if a property defined on a class doesn't include a JSDoc description.

For example, with the following code I would expect a message regarding id, mainCharacters, and state missing JSDoc descriptions.

export default class Party {
    public id = -1;
    public mainCharacters: Character[] = [];
    public state: PartyState;
    /**
     * Location index.
     */
    public location = 0;

Based upon the documentation it doesn't appear the jsdoc/require-property* rules would work, but I did try switching them on anyway and they're not reporting missing JSDocs.

'jsdoc/require-property': 1,
'jsdoc/require-property-description': 1,
'jsdoc/require-property-name': 1,
'jsdoc/require-property-type': 1,

What ESLint rule(s) am I missing that would report missing JSDocs on TypeScript properties?


Solution

  • Firstly, I should note that eslint-plugin-jsdoc's rules are incremental. If you don't have any jsdoc block at all, you first need to add the jsdoc/require-jsdoc rule so it will complain unless you have at least something like:

    /**
     *
     */
    

    ...above your structure of interest. In your case, you do have "recommended" which includes this rule, so you're covered there.

    Similarly, the rules like require-property-description or require-property-name will only work if you already have a @property on a given block.

    Secondly, the require-property rule has a different purpose than what you are trying to do. It is instead used to report that a @property is present when a jsdoc block has a @namespace tag (used for plain objects) or a @typedef tag (used for defining types).

    JSDoc does indicate the tag can be used for the static properties of classes, so the eslint-plugin-jsdoc project could in theory adapt the rule to check for consistency between any @property tags in a jsdoc block above the class and those properties used within the class, but I'm not sure how popular this would be given that most projects seem to prefer adding the docs in the manner in your example (i.e., above the properties themselves).

    You could use require-property, along with the other require-property-* rules too if you used the @property tag right above your properties, but I wouldn't think you would really want that, especially since I'm not sure how documentation tools treat @property in this context--it seems from the TypeScript docs that @type is used instead--to check that @type has a curly-bracketed type, use jsdoc/valid-types and you could use jsdoc/match-description to indicate that the tag should have a description or use jsdoc/require-description so as to enforce a description above the tag, using either of these two description-related rules' contexts option with ClassProperty inside since they don't check properties by default).

    But to finally get back to the most important part of what you need, you will want to use jsdoc/require-jsdoc. However, by default require-jsdoc only checks for FunctionDeclaration, i.e., for regular function declarations, but you can use the require or contexts option for more precise control, i.e., in your case you could add {contexts: ['ClassProperty']}.