Типизация JavaScript через JSDoc: Руководство по настройке TypeScript Compiler
Введение: От основ к профессиональной настройке
Если вы уже используете JSDoc для описания типов в вашем JavaScript-коде и ощутили пользу от подсказок в редакторе — сделали только первый, хотя и самый важный, шаг. Мощь этого подхода раскрывается полностью, когда вы выходите за пределы редактора и подключаете проверку типов на уровне всего проекта, в процессе сборки и непрерывной интеграции (CI).
Эта статья — продолжение введения в JSDoc. Здесь не будет объяснений, что такое @type или @param. Вместо этого сфокусируемся на инструментарии и конфигурации, которые превращают набор JSDoc-комментариев в строгую систему типов для всего проекта. Вы научитесь настраивать TypeScript Compiler (tsc) для работы с .js-файлами, генерировать файлы деклараций (.d.ts) и автоматизировать проверки.
Быстрый старт: от нуля до полной проверки за 5 минут
Этот раздел — ваша шпаргалка для немедленного внедрения. Предполагается, что TypeScript уже установлен как dev-зависимость (npm install -D typescript).
Шаг 1: Включение проверки в файле:
Добавьте директиву // @ts-check в начало любого .js-файла, чтобы TypeScript Language Server начал его агрессивно анализировать.
// @ts-check
/** @type {string} */
let greeting = "Hello";
greeting = 100; // Немедленно: Type Error!Шаг 2: Глобальная настройка проекта (jsconfig.json):
Для применения правил ко всему проекту создайте в корне jsconfig.json. Это аналог tsconfig.json для JavaScript-проектов.
{
"compilerOptions": {
"checkJs": true, // Включает проверку типов для всех .js файлов
"strictNullChecks": true, // Включает одну из строгих опций
"module": "ESNext",
"target": "ES2022"
},
"include": ["src/**/*"] // Какие файлы проверять
}Ключевая опция checkJs — это «волшебный выключатель», который активирует фоновую проверку типов для всего кода в редакторе.
Шаг 3: Запуск проверки из терминала:
Добавьте скрипт в package.json для проверки всего проекта:
{
"scripts": {
"type-check": "tsc --noEmit --project jsconfig.json"
}
}Запустите npm run type-check. Команда tsc --noEmit запустит компилятор, но не будет создавать никаких выходных файлов — только проверит типы и выведет ошибки в терминал. Это основа для CI.
Генерация файлов .d.ts: Делаем вашу библиотеку дружелюбной к TypeScript
Если создаёте библиотеку на чистом JavaScript, ваши пользователи, работающие в TypeScript-проектах, будут ожидать файлы деклараций типов (.d.ts). Их можно сгенерировать автоматически из JSDoc-комментариев.
Для этого создайте отдельный tsconfig.declaration.json:
{
"include": ["src/**/*.js"], // Исходные .js файлы
"compilerOptions": {
"allowJs": true, // Разрешить обработку .js файлов
"declaration": true, // Генерировать .d.ts файлы
"emitDeclarationOnly": true, // Не выводить .js (у нас они уже есть)
"outDir": "dist/types", // Куда положить .d.ts файлы
"declarationMap": true // Для удобной навигации "Go to Definition"
}
}Добавьте скрипт сборки в package.json:
{
"scripts": {
"build:types": "tsc -p tsconfig.declaration.json"
}
}После запуска npm run build:types в папке dist/types появятся файлы .d.ts, полностью отражающие типы, описанные в JSDoc. Укажите путь к ним в package.json вашей библиотеки:
{
"types": "./dist/types/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/types/index.d.ts"
}
}
}Теперь JS-библиотека будет обеспечивать идеальный опыт разработки в TypeScript-проектах.
Продвинутые паттерны JSDoc для сложных сценариев
Когда выходите за рамки базовых типов, JSDoc предоставляет всю необходимую выразительность.
Импорт и переиспользование сложных типов
Для типов, определённых в других файлах (например, в собственном коде или в сторонних библиотеках без типов), используйте @typedef с импортом.
// src/types.js
/**
* @typedef {Object} User
* @property {number} id
* @property {string} name
*/
export {};
// src/controller.js
/**
* @typedef {import('./types.js').User} User
* @typedef {import('some-js-lib').ExternalConfig} Config
*/
/**
* @param {User} user
* @param {Config} config
*/
export function processUser(user, config) { /* ... */ }Типизация для реактивных и DOM-манипуляций
Работа с DOM API или фреймворками часто требует указания конкретных типов элементов.
// Типизация элемента DOM
/** @type {HTMLInputElement | null} */
const searchInput = document.querySelector('.search-input');
// Типизация в обработчике события
element.addEventListener('click', (/** @type {MouseEvent} */ evt) => {
// evt теперь имеет тип MouseEvent
});
// Типизация для фреймворка (пример с htmx)
htmx.defineExtension("my-ext", {
onEvent: (name, /** @type {CustomEvent} */ event) => {
// event теперь типизирован как CustomEvent
}
});Обход проверки в исключительных случаях
Иногда TypeScript не может корректно вывести тип, или вы намеренно делаете что-то, что выходит за рамки системы типов. В таких случаях используйте осознанные исключения.
// 1. @ts-ignore - отключает проверку для следующей строки (используйте редко).
// @ts-ignore
const legacyData = getDataFromUnsafeSource();
// 2. @ts-expect-error - ожидает ошибку. Лучшая практика, так как падает, если ошибки нет.
function strictParse(input) {
// Мы уверены, что parse может выбросить ошибку, которую мы обработаем.
// @ts-expect-error
return unsafeParse(input);
}
// 3. Приведение типа (Type Assertion) через JSDoc
const element = /** @type {HTMLElement} */ (document.querySelector('.dynamic-widget'));Настройка CI/CD
Статическая типизация приносит максимальную пользу, когда она обязательна для всего кода, попадающего в основную ветку. Интегрируйте проверку типов в ваш процесс CI/CD.
Базовый шаг для GitHub Actions (.github/workflows/type-check.yml):
name: Type Check
on: [push, pull_request]
jobs:
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
check-latest: true
- run: npm ci
- run: npm run type-check # Скрипт, который мы создали ранееЭтот workflow будет запускаться при каждом пуше и пул-реквесте, блокируя слияние кода, содержащего ошибки типов.
Заключение: JavaScript с типизацией enterprise-уровня
Использование JSDoc в паре с TypeScript Compiler — это не «хак», а легитимная, мощная и промышленно пригодная методология. Она позволяет:
- Создавать и поддерживать крупные кодовые базы на чистом JavaScript, не жертвуя надёжностью, которой славится TypeScript.
- Иметь итерационный цикл разработки без задержек на сборку, получая при этом всю интеллектуальную помощь редактора.
- Построить сквозной процесс гарантии качества — от написания кода до слияния в main — через статический анализ.
- Создавать библиотеки, которые одинаково хорошо работают в проектах на JavaScript и TypeScript.
Как показано в первой части руководства, начать использовать JSDoc невероятно просто. А как вы только что узнали, — нет предела глубине его интеграции в профессиональный рабочий процесс. Вы получаете всю мощь экосистемы TypeScript, оставаясь при этом в рамках нативных стандартов веб-платформы.
Начните с настройки jsconfig.json и скрипта type-check сегодня — и ваш JavaScript-код завтра станет значительно более предсказуемым, сопровождаемым и безопасным.