JSDoc - reusing type definitions error (cannot find name ‘type name’)
Asked Answered
B

1

2

I have the following project structure:

api/
  users/
    users.d.js

contexts/
  users/
    users.d.js

utils/
  users/
    users.d.js

In utils/users/users.d.js I am defining the types that are reusable through the whole system.

For example, the following type:

/**
 * Represents a User.
 *
 * @typedef {object} User
 * @property {string} id - Unique identifier.
 * …
 * @property {Date} birthday - Birthday.
 */

This is cool, now I can reuse it in my module index.js as follows:

import “./utils/users/users.d”;

/**
 * …
 * @param {User} user - The profile owner.
 */
function navigateToUserProfile(user) {
  …
}

And that works fine! My code editor detects the type and the documentation can be auto generated without problems :)

But… what if api/users/users.d.js requires that global type definition?

For example, what if in that module I have the following definition:

/**
 * @typedef {object} EditProfileInterface
 *
 * @property {User} newUserData - The new user data.
 * …
 */

In order to reuse the global definition, I would need to import the utility module (utils/users/users.d.js) in the “local type definitions” module (api/users/users.d.js).

Okey… so, let just do:

// this code is inside api/users/users.d.js
import “../../utils/users/users.d”;

as we did inside index.js.

Here is where my problem comes. After doing this, JSDOC is not able to generate the documentation correctly any more. It moves the type definitions of api/users/users.d.js to the global section of the documentation.

Also, if I do // @ts-check inside a module that imports api/users/users.d.js, I get the error Cannot find name ‘EditProfileInterface’ (unresolved type). This is making really difficult the types reusability… it seems that there is no more options than duplicating the definitions between modules (?)

Any suggestions or workarounds? Should I just don’t care about duplicating type definitions between different modules?

Bowyer answered 16/2, 2022 at 21:8 Comment(0)
B
5

The trick is to configurate JSDoc to support typescript mode.

1- Create a jsconfig.json file in order to active ts-check in your whole project:

This is the code I use:

{
  "compilerOptions": {
    "baseUrl": ".",
    "module": "commonjs",
    "target": "es2021",
    "jsx": "react-native",
    "checkJs": true, <--- ACTIVES the @ts-check directive in every single module of your project in order to avoid bugs :) 
  },
  "include": ["app/**/*.d.js", "app/**/*.js", "app/**/*.cjs", "app/**/*.mjs", "app/**/*.jsx"],
  "exclude": ["node_modules", "./functions/", "./docs"]
}

If you get a linting error, just re-open VSCode.

2- Install this development dependency: jsdoc-tsimport-plugin

yarn add --dev jsdoc-tsimport-plugin

3- In your jsdoc config file, add the installed plugin:

module.exports = {
  plugins: [
    "plugins/markdown",
    "node_modules/better-docs/category",
    "node_modules/jsdoc-tsimport-plugin/index.js", <------- THIS!
  ],
  source: {
    include: [
      "Main.jsx",
      "app/",
      "functions/",
      "shared/",
    ],
    includePattern: ".+\\.(js(doc|x)?|(m|c)js)$",
    excludePattern: "(node_modules/|docs)",
  },
  sourceType: "module",
  tags: {
    allowUnknownTags: true,
    dictionaries: ["jsdoc", "closure"],
  },
  ...

4- In your eslint configuration file, add the following setting:

  extends: [
    "eslint:recommended",
    "airbnb",
    "prettier",
    "plugin:react/recommended",
    "plugin:react-native/all",
    "plugin:jsx-a11y/recommended",
    "plugin:react-hooks/recommended",
    "plugin:import/recommended",
    "plugin:flowtype/recommended",
    "plugin:jsdoc/recommended",
  ],
  settings: {
    jsdoc: {
      mode: "typescript", <--- THIS!
    },
  },
  rules: {
  ...

NOW, YOU CAN USE THE TYPESCRIPT SYNTAX WITH JSDOC

For example, in this project structure:

shared/
   types.d.js

api/
   users/
      users.d.js

You can define a type in your global types (inside the shared folder):

/**
  * Some description for the type definition.
  *
  * @typedef SomeGlobalType
  * @property {string} [text="Hello world"] - Description for the property.
  */

And then, simply import it inside api/users/users.d.js, like this:

 /**
  * @typedef User
  * @property {import("../../shared/types.d").SomeGlobalType} tricky - HEHE 
  */

Thats all ;)

Bowyer answered 17/2, 2022 at 11:10 Comment(1)
Also, make sure that in your .d.js modules you export something! for example export {}, to avoid linting errors.Bowyer

© 2022 - 2024 — McMap. All rights reserved.