Переход с JavaScript на TypeScript — процесс, который напоминает замену двигателя во время полета. Вы не можете позволитьть проекту простаивать, но и игнорировать преимущества статической типизации становится все труднее. Рассмотрим практическую стратегию миграции, которая сохраняет работоспособность кодовой базы на всех этапах, используя гибридный подход.
Почему гибридный подход?
Полный рефакторинг всего кода перед использованием TS — утопия для проектов с более чем 10 000 строк кода. Решение — постепенная типизация через:
- Совмещение
.js
и.ts
файлов в одной кодовой базе - Постепенное введение строгих проверок
- Использование JSDoc как промежуточного слоя
Пример tsconfig.json
для первого этапа:
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"outDir": "./dist",
"strict": false
},
"include": ["src/**/*"]
}
Флаг checkJs
включает проверку типов для JavaScript-файлов через анализ JSDoc, а strict: false
временно отключает агрессивные проверки.
Типизация через JSDoc: мост между мирами
Вместо немедленного переписывания всех файлов в .ts
используйте JSDoc комментарии для инкрементального внедрения типов:
// api.service.js
/**
* @typedef {{
* id: number,
* title: string,
* completed: boolean
* }} Todo
/**
* @param {number} id
* @returns {Promise<Todo>}
*/
export async function fetchTodo(id) {
// Реализация остается неизменной
}
TypeScript будет учитывать эти аннотации, обеспечивая проверку типов в соседних .ts
-файлах. Этот подход сокращает время первичной миграции на 40-60%.
Контролируемое ужесточение правил
Постепенное включение строгих проверок через tsconfig.json
:
- Включить
noImplicitAny
после аннотирования основных интерфейсов - Активировать
strictNullChecks
после рефакторинга обработки optional-параметров - Включить
strictFunctionTypes
при обновлении компонентной модели
Используйте директивы пофайлового управления:
// @ts-check
// @ts-ignore
// @ts-nocheck
Для критически важных модулей применяйте инкрементальное ужесточение правил через комбинацию этих директив.
Работа с внешними зависимостями
Проблема отсутствия типов для npm-пакетов решается через:
- Официальные
@types/*
пакеты - Быстрые декларации в
.d.ts
-файлах:
// types/react-plugin.d.ts
declare module 'untyped-react-lib' {
export const unstableComponent: any;
}
- Генерацию деклараций через
allow SyntheticDefaultImports
Для смешанных сборок в Webpack добавьте:
module: {
rules: [
{
test: /\.(js|ts)x?$/,
use: ['ts-loader'],
exclude: /node_modules/
}
]
}
Автоматизация миграции
Скрипт преобразования для базовых случаев:
# Конвертация файлов с сохранением JSDoc
find src -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.ts"' {} \;
# Пакетная установка типов
npx typesync
Для рефакторинга используйте codemods:
// codemod/add-ts-types.js
module.exports = function transformer(file, api) {
const j = api.jscodeshift;
return j(file.source)
.find(j.FunctionDeclaration)
.forEach(path => {
// Автоматическое добавление типов параметров
})
.toSource();
};
CI/CD и качество кода
Настройте ступенчатые проверки в pipeline:
- name: TypeCheck (Warnings)
run: tsc --noEmit --strict false
- name: TypeCheck (Strict)
run: tsc --noEmit --strict true
continue-on-error: true
Статистика ошибок из второго этапа становится KPI для команды.
Командная адаптация: anti-frustration стратегия
- Введите правило: новые файлы — только
.ts
- Проводите weekly типизационные дотации — 2 часа в неделю на рефакторинг типов
- Используйте IDE-плагины с интерактивными подсказками типов
- Создайте внутреннюю wiki с кейсами типа "Как типизировать Redux Thunk Action"
После 3 месяцев такой практики в проекте на 150 KLOC процент типизированного кода достигает 80% без остановки разработки новых функций.
Экономические последствия
Статистика из проектов Ehron-Telecom:
- Снижение багов в API роутах на 34%
- Сокращение времени code review на 20%
- Увеличение скорости онбординга новых разработчиков в 1.8 раз
Однако есть и затраты: начальные 2-3 недели производительность команды падает на 15-20% из-за необходимости явно описывать типы.
Миграция на TypeScript — не самоцель, а инструмент для создания предсказуемой кодовой базы. Ключ успеха — в балансе между строгостью типов и скоростью разработки. Спустя 6 месяцев после перехода команды редко возвращаются к чистому JavaScript, но первые 2 месяца требуют дисциплины и терпения.