Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSDoc typedef in a separate file

Tags:

jsdoc

Can I define all custom types in a separate file (e.g. types.jsdoc), so that they can be reused throughout the application? What's the right way to do it?

/**
 * 2d coordinates.
 * @typedef {Object} Coordinates
 * @property {Number} x - Coordinate x.
 * @property {Number} y - Coordinate y.
 */
like image 664
Edward Ruchevits Avatar asked Apr 03 '17 11:04

Edward Ruchevits


3 Answers

You can define types in a module (eg. typedefs.js). The module contains your JSDoc typdefs and can simply export an unused property.

// typedefs.js
/**
 * @typdef foo
 * @property {string} bar
 */

// etc.

exports.unused = {};

To use it, import the module where you need to reference these typdefs:

const typedefs = require("./typedefs");
/** @type {typedefs.foo} */
const fb = { bar: "hello" };

You may wish to annotate typedefs.js as a @module or @namespace. Because I'm using "tsd-jsdoc" to generate a types.d.ts file, and due to the way TypeScript now interprets modules vs. namespaces, I've annotated my typedefs.js file as a @namespace and documented each typedef as a member of that namespace:

/**
 * @namespace typedefs
 */

/**
 * @typedef foo
 * @property {string} bar
 * @memberof typdefs
 */

Hope that helps.

like image 157
Darren Avatar answered Nov 06 '22 18:11

Darren


This is a TypeScript-flavored JSDoc specific answer, but I'm having success using a triple-slash directive to "import" all the types from another file. This has the advantage of not actually adding an unused import which can upset linters and bundlers.

I'm putting my shared types in one file called typedefs.js like this:

// typedefs.js
/**
 * @typedef {Object} Foo
 * @property {string} bar
 */

/**
 * @typedef {Object} Baz
 * @property {number} buzz
 */

and then using /// <reference path="typedefs.js" /> in the other files to access the shared types like this:

// randomThing.js
/// <reference path="typedefs.js" />

/**
 * Turn a Foo into a Baz
 *
 * @param {Foo} a
 * @return {Baz}
export function (a) {
  return { buzz: a.bar.length };
}

The tricky thing though is that now typedefs.js is just being referenced in a comment, bundlers like rollup miss it completely. So I'm combining it with my old consts.js that exports a few constants and is imported in at least one place. That way the typedefs are still included in the rollup output.

I hope someone else finds this helpful.

p.s. rollup will completely exclude a pure JSDoc typedefs.js file _even if you have import './typedefs.js' because of tree-shaking! Gotta run rollup with --no-treeshake to keep those comments in the rollup output.

like image 12
William Hilton Avatar answered Nov 06 '22 20:11

William Hilton


In vscode, the import('./path/to/types.js').def tag works perfectly fine.

For e.g.
types.js

/**
 * @typedef {Object} connection
 * @property {String} id
 * @property {Number} pingRetries
 * @property {(data:Object) => void} sendJSON
 */
exports.unused = {};

And someFile.js

/**
 * @param {import('./types').connection} param
 */
const someFunc = (param) => {}

Also, note that the exports.unused = {} is necessary in the types.js file, otherwise the auto-import of import('./types') would not work and you may have to type it by yourself.

like image 6
Shivam Goyal Avatar answered Nov 06 '22 18:11

Shivam Goyal