Я использую JSDoc уже некоторое время, и в связи с недавней шумихой из-за миграции Svelte, сегодня я пришел поделиться советами и тем, как их использовать.

Это самые основы того, что вам понадобится.

Машинопись

Синтаксис для некоторых вещей отличается, но для большинства вещей просто думайте об этом как о Typescript, и все будет в порядке.

файлы .d.ts

Я обычно использую их для вспомогательных и служебных типов (их проще создать, особенно с дженериками, и потом их можно просто использовать)

Настраивать

Добавьте // @ts-check в начало каждого файла, который вам нужен, или добавьте jsconfig,json в корень вашего проекта с проверочными JS-файлами. (Не забудьте включить js checking в вашей IDE).

JSDoc

@тип

Как и в случае с TS, есть разница между:

/** @type {Foo} */
const foo = {}
const foo: Foo = {}

// and

const foo = /** @type {Foo} */ ({})
const foo = {} as Foo

// also includes
const foo = /** @satisfies {Foo} */ ({})

В зависимости от того, как вы хотите, чтобы TS обрабатывал тип, автозаполнение и ошибки, которые он вам показывает.

Для @type я обычно делаю это встроенным, потому что я обычно использую его для приведения чего-то к нужному мне типу:

// React common example
const [state, setState] = useState(/** @type {{ foo: Bar, bar: Baz }} */ ({}));
//     ^? { foo: Bar, bar: Baz }

// And then sometimes you need some casting
Object.keys(state).map(k => k)
//                     ^? string

/** @type {(keyof state)[]} */ (Object.keys(state)).map(k => k)
//                                                      ^? "foo"|"bar"

И, как вы могли видеть, при приведении чего-то к типу вы заключаете его в круглые скобки /** @type {Foo} */ (toBeCast), и, конечно, если вам нужно, вы можете /** @type {Foo} */(/** @type {unknown} */ (toBeCast)) и да, для этого вам нужно поместить его внутрь двух.

@typedef

Вы, вероятно, будете использовать много, обычно для более сложных типов.

Для этого я объявляю его как блок и обычно первым способом без каких-либо комментариев.

Но иногда вам нужна вторая версия, потому что куда бы ни пошли эти типы, там же и комментарии.

/**
 * @template {string} [T='bar']
 * @typedef {{
 *  bar: T, // you can't see this comment
 *  baz?: string,
 * }} Foo visible comments here
 */

/**
 * @template {string} [T='bar']
 * @typedef {Object} Foo2
 * @property {T} bar this comment is visible
 * @property {string} [baz] this is an optional property
 */

// both equivalent to:
type Foo<T extends string = "bar"> = {
  bar: T;
  baz?: string;
}

Что касается @template, самый простой способ объявить дженерик — это @template T.

Тот, что в примере, является самым сложным, который вам понадобится, с типом, который он расширяет, а затем значением по умолчанию, но вы также можете иметь только одно или другое.