Долгое время моей IDE была PhpStorm. Для JavaScript я опирался на JSDoc как на язык контрактов: сигнатуры, навигация, автодополнение. Всё работало стабильно, предсказуемо и привычно. Но переход в Visual Studio Code оказался неожиданно болезненным. Анализ JavaScript-кода стал менее устойчивым. Предупреждения и сообщения формулируются в терминах TypeScript, который я не использую по "религиозным соображениям". JSDoc присутствует, но в инфраструктурном и библиотечном коде его влияние практически исчезает.

Ключевой факт, который это объясняет: JavaScript в VSCode анализируется как проекция TypeScript-модели через tsserver. Первый практический сигнал - jsconfig.json. Без него JavaScript анализируется фрагментарно:

{
  "compilerOptions": {
    "checkJs": true
  }
}

После добавления файла проект начинает восприниматься как целостный: появляются связи между файлами, навигация, типовые подсказки. Сам JS-код при этом не меняется. Этот файл не участвует в выполнении и не относится к стандарту JavaScript. Он нужен только анализатору VSCode, в PhpStorm я прекрасно обходился без него.

Но VSCode код сам не анализирует. Все подсказки и навигация приходят от tsserver. Связь с ним осуществляется через LSP. Поведение IDE полностью определяется возможностями выбранного language server’а. Для JavaScript в реальной практике используется только tsserver; JS-first или JSDoc-first альтернатив для анализатора нет (нет, Microsoft не делал и не собирается делать подобрных альтернатив).

tsserver строит модель проекта на основе статических импортов в границах, заданных jsconfig.json. Всё, что определяется динамически или формируется на этапе выполнения, в эту модель не попадает.

Я хорошо ощущаю это в собственных проектах. В их архитектуре используется позднее связывание и внедрение зависимостей через конструктор, реализованное в моей библиотеке @teqfw/di. Статические импорты сведены к минимуму - фактически только для загрузки самой DI-библиотеки. Всё дальнейшее связывание происходит динамически и остаётся за пределами возможностей анализа tsserver.

На уровне библиотек ограничения анализа преодолеваются через механизм публичных контрактов. При анализе внешнего проекта VSCode опирается не на JavaScript-код npm-зависимости, а на файл деклараций, указанный в package.json в поле types. Именно этот файл используется tsserver для построения типовой модели зависимости. Реализация библиотеки и JSDoc-аннотации внутри node_modules в анализ потребляющего проекта не включаются.

JSDoc в этой схеме работает только в той мере, в какой его можно однозначно свести к типовой проекции. Семантические и поведенческие аспекты в модель типов не попадают.

В итоге в VSCode нет отдельного режима анализа "чистого JavaScript". Существует единая TypeScript-ориентированная модель, и JavaScript анализируется ровно настолько, насколько его форма допускает такую проекцию.

Это границы инструмента (VSCode). Когда их принимаешь, поведение IDE становится чуть более предсказуемым и понятным.

P.S.

Данная публикация является "выжимкой" (конспектом) более полного изложения этой же информации и сделана специально для Хабра в рамках изучения принципа первичного принятия знания (это моя формулировка, можете даже не гуглить). Если вам уже знакомо всё, что я "выжал", или просто не интересно - считайте, что сэкономили время, не ознакомившись с полным изложением. Если хотите что-либо обсудить - welcome в комменты прямо тут.

P.P.S.

И этот конспект, и полное изложение делались с применением LLM. Если вас такое на Хабре не устраивает и вы хотите поставить статье "минус", большая просьба - поставьте на меня фильтр в своей ленте, чтобы я вам больше не попадался и не раздражал. Ищите вот этот вот функционал в правом углу сразу под публикацией:

Кликайте по шестерёнке и затем "Скрыть публикации автора"
Кликайте по шестерёнке и затем "Скрыть публикации автора"

Комментарии (5)


  1. Kwisatz
    24.12.2025 22:16

    Вы знаете, а я вот наоборот вынужден был дойти до TS, потому что анализ Storm,Idea/etc JS кода оставляет желать лучшего, но что одно что другое вгоняет меня в ступор. И в том числе изза того что вы указали. Но ТС со своим контрактами уровня "мамой клянусь" и странными практиками (а давайте везде весело ставить нулы) и без нормального рантайм функционала типо полноценной рефлексии вызывает у меня ощущения, что за 20 лет в JS мире не изменилось вообще ничего.


    1. flancer Автор
      24.12.2025 22:16

      Без JSDoc'ов анализ JS-кода вообще очень печален в любой IDE. А с JSDoc'ами анализатор IDEA очень даже неплохо с кодом управлялся. Может и похуже Java/JavaDoc, но точно не хуже, чем PHP/PhpDoc.


      1. Kwisatz
        24.12.2025 22:16

        Без них я вообще не знаю как люди живут. И все же похуже Java/Php: постоянно недоумеваю почему в js файлах у меня нет предупреждения о том что свойства такого у объекта просто нет, иногда просто тип не распознается, некоторые хинты по месту тупо не работают через раз. Я последние полгода живу буквально с ними в обнимку, наелся)


  1. divinity2000
    24.12.2025 22:16

    Т.е. основная проблема в том что вы используете DI, но не понимаете как как подружить с ним typescript, который по своей сути является совокупностью JSDocs и транспилятора babel (это отсылка к религиозным соображениям, не в обиду :) )

    Во vue.js, например, есть механизмы позволяющие выполнять инъекции кода в экземпляр для работы в рантайме и там же есть возможность выполнить инъекцию в исходный интерфейс для того чтобы тот же language server в vscode отработал корректно (и в других редакторах или ide тоже)

    Работает это все через декларирование глобальных типов/модулей и их перегрузку, если это можно так назвать

    Возможно это то что вы ищите


    1. flancer Автор
      24.12.2025 22:16

      Не совсем так. Я использую DI через конструкторы в чистом JS. Без транспиляции вообще. Дело не в TS, а в транспиляции (любой). Если (когда) EcmaScript по своему синтаксису приблизится вплотную к TypeScript - я спокойно буду указывать типы в сигнатурах функций. Я так уже делал - в PHP. Там до версии 5 было всё то же самое, что в JS сейчас.

      Но я когда-то писал код на Java под GWT и транспилировал его в JavaScript. Тогда-то ко мне и пришло осознание, что когда мы транспилируем один язык в другой, то их недостатки суммируются, а достоинства - нет. Так что тут дело не в синтаксисе TypeScript, а в транспиляции как таковой.

      У меня довольно неплохо работал JSDoc в PhpStorm. Как оказалось, это PhpStorm довольно неплохо работал с JSDoc :) Я использовал и автодополнение, и навигацию по коду, и документирование во всплывающих подсказках. В общем всё, что мне давала типизация в PHP/Java. Но этот же самый код переставал обслуживаться "в самой популярной IDE для JS-мира". И это озадачивало.

      Ответ, на мой взгляд, в том, что Microsoft не будет развивать один свой продукт (VSCode) в ущерб другому своему продукту (TypeScript). Не будет нативной поддержки JSDoc в VSCode от Microsoft. Даже если код написан на чистом JS, всё равно нужен файл jsconfig.json и запись "types": "types.d.ts" в package.json, если проект планируется использовать с VSCode (или с любым другим редактором кода с возможностью интеграции c tsserver по LSP). Если будет "другой хороший JSDoc-анализатор" с возможностью подключения по LSP, то у него будут свои правила (свой "jsconfig.json").

      Ну а пока, да - придётся декларировать всё мало-мальски значимое в types.d.ts , чтобы tsserver мог это видеть.