Reputation: 6696
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.
*/
Upvotes: 63
Views: 26509
Reputation: 467
To import types from another file, you can use these Typescript 5.5 directives:
/** @import {foo, bar} from './typedefs.js' */ // for several types
/** @import * as types from './typedefs.js' */ // for all types
/** @type {foo} */
const foo1 = 'foo';
/** @type {types.foo} */
const foo2 = 'foo';
An empty export must be specified in the typedefs.js
file:
export {};
/** @typedef {string} foo */
/** @typedef {number} bar */
This works for me fine with VSCode 1.95.3 and ESLint 9.15.0 with eslint-plugin-jsdoc 50.6.0.
I do not know if this works in WebStorm or other IDE.
Upvotes: 1
Reputation: 2024
You can define types in a module (eg. typedefs.js
). The module contains your JSDoc typedefs and can simply export an unused property.
// typedefs.js
/**
* @typedef foo
* @property {string} bar
*/
// etc.
exports.unused = {};
// or export {};
To use it, import the module where you need to reference these typedefs:
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 typedefs
*/
Hope that helps.
Upvotes: 28
Reputation: 71
I've had success with simply creating my types in a typedefs.js
file and referencing using the ts/vscode import(path/to/file).Foo
tag. JSDoc does not support this syntax out of the box, so I suggest also using jsdoc-tsimport-plugin in order to parse your docs.
Eg: typedef.js:
/**
* @typedef {Object} Foo
* @property {string} id
*/
/**
* @typedef {Object} Bar
* @property {string[]} things
*/
// having to export an empty object here is annoying,
// but required for vscode to pass on your types.
export {};
coolFunction.js
/**
* This function is super dope
* @param {import('../typedef').Foo[]} foo - a foo
* @return {import('../typedef').Bar[]} bar - an array of bars
*/
export function (foo) {
// do cool things
return bar;
}
I'm also using tsd-jsdoc to create a types.d.ts
file, and this implementation is successfully creating the types. I had trouble with declaring modules
and namespaces
with the types file— just creating standalone typedefs
for said models worked best for me.
Upvotes: 2
Reputation: 91
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.
Upvotes: 8
Reputation: 3133
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.
Upvotes: 16
Reputation: 91
I just tried with VSCode and it works only if the separate file is opened in the editor. If not, external typedefs are typed as any
Upvotes: 4
Reputation: 20736
I usually do something similar in my projects, the difference being I use the extension .js
to name the file. Webstorm works perfectly and is able to check types and auto-complete just fine. It won't recognize the .jsdoc
extension (I just checked), so stick to .js
even if the file doesn't contain any code statement.
Upvotes: 2