Антон Ларичев

Введение
Миграция с JavaScript на TypeScript — один из самых частых запросов в современных командах разработки. Статическая типизация помогает находить ошибки на этапе компиляции, улучшает автодополнение в редакторе и делает рефакторинг безопасным. Но многие разработчики откладывают перевод проекта на TypeScript, потому что боятся сломать рабочий код или потратить недели на переписывание.
На самом деле миграция с JavaScript на TypeScript может быть постепенной и безболезненной. TypeScript — это надмножество JavaScript, и каждый валидный JS-файл уже является валидным TS-файлом. Это значит, что вам не нужно переписывать весь проект за один день. В этом руководстве мы разберём пошаговый план перехода, который позволит продолжать разработку новых фич параллельно с миграцией.
Подготовка проекта к переходу на TypeScript
Первый шаг — установка TypeScript и создание файла конфигурации. Это не затронет существующий код и не повлияет на работу приложения.
# Установка TypeScript как dev-зависимости
npm install --save-dev typescript
# Создание базового tsconfig.json
npx tsc --init
Как настроить tsconfig для миграции
Ключевой момент — правильная настройка tsconfig.json. На начальном этапе не включайте строгий режим, иначе компилятор выдаст сотни ошибок сразу. Начните с мягких настроек:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"allowJs": true,
"checkJs": false,
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Обратите внимание на allowJs: true — это позволяет TypeScript-компилятору обрабатывать как .ts, так и .js файлы. Вы можете переименовывать файлы по одному, не ломая сборку.
Постепенная миграция файлов: пошаговый план
Не пытайтесь переименовать все файлы разом. Правильная стратегия — постепенная миграция, файл за файлом, начиная с ядра приложения.
Шаг 1: Определите порядок миграции
Начинайте с файлов, от которых зависят другие модули — утилиты, типы данных, конфигурация. Так типизация начнёт распространяться по проекту естественным образом.
// utils/validation.ts — начинаем с утилит
export function isEmail(value: string): boolean {
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return pattern.test(value);
}
export function isEmpty(value: unknown): boolean {
if (value === null || value === undefined) return true;
if (typeof value === 'string') return value.trim().length === 0;
if (Array.isArray(value)) return value.length === 0;
return false;
}
Шаг 2: Создайте интерфейсы для основных сущностей
Определите типы и интерфейсы для ключевых объектов вашего приложения в отдельной директории:
// types/user.ts — описываем основные сущности
export interface User {
id: number;
email: string;
name: string;
role: 'admin' | 'user' | 'moderator';
createdAt: Date;
}
export interface CreateUserDto {
email: string;
name: string;
password: string;
}
Шаг 3: Переименовывайте и типизируйте
Переименуйте файл из .js в .ts и добавьте аннотации типов. На начальном этапе допустимо использовать any для сложных мест, но фиксируйте такие места комментарием:
// service/user.service.ts
import { User, CreateUserDto } from '../types/user';
export class UserService {
// TODO: типизировать после миграции database.js
private db: any;
constructor(database: any) {
this.db = database;
}
async findById(id: number): Promise<User | null> {
return this.db.query('SELECT * FROM users WHERE id = $1', [id]);
}
async create(dto: CreateUserDto): Promise<User> {
const { email, name, password } = dto;
return this.db.query(
'INSERT INTO users (email, name, password) VALUES ($1, $2, $3) RETURNING *',
[email, name, password]
);
}
}
Добавление типов для сторонних библиотек
Многие npm-пакеты уже поставляются с встроенными определениями типов. Для остальных существует репозиторий DefinitelyTyped с пакетами @types/*:
# Установка типов для популярных библиотек
npm install --save-dev @types/node @types/express @types/lodash
Если для библиотеки нет готовых типов, создайте файл декларации:
// types/custom-lib.d.ts — декларация для библиотеки без типов
declare module 'custom-lib' {
export function doSomething(input: string): Promise<string>;
}
Включение строгого режима после миграции
Когда большинство файлов переведены на TypeScript, пора включать строгие проверки. Делайте это поэтапно, добавляя по одному флагу:
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true
}
}
Включайте флаги по одному, исправляя ошибки после каждого. Порядок включения:
noImplicitAny— запрещает неявный тип anystrictNullChecks— запрещает null и undefined там, где они не ожидаютсяstrictFunctionTypes— строгая проверка типов параметров функцийstrict: true— включает все проверки разом
Частые ошибки при переходе с JS на TS
При миграции с JavaScript на TypeScript разработчики часто допускают одни и те же ошибки:
Включение strict с первого дня. Строгий режим выдаст сотни ошибок в непереведённых файлах, что демотивирует команду. Начинайте с мягких настроек.
Использование any повсюду. Тип any отключает проверку типов и сводит на нет преимущества TypeScript. Используйте unknown вместо any, когда тип действительно неизвестен.
Миграция всего проекта за один раз. Попытка перевести весь проект разом приводит к огромному PR, который невозможно нормально проревьюить. Мигрируйте по модулям.
Игнорирование автоматических инструментов. Утилита ts-migrate от Airbnb автоматически конвертирует JS-файлы в TS, расставляя any там, где нужна типизация. Это ускоряет начальный этап.
# Автоматическая миграция через ts-migrate
npx ts-migrate-full ./src
Заключение
Миграция с JavaScript на TypeScript — это инвестиция, которая окупается за счёт снижения количества багов, улучшения документации кода и ускорения разработки. Главное правило — мигрируйте постепенно, используйте allowJs для совместимости, начинайте с ядра приложения и включайте строгие проверки только после перевода основных модулей. При таком подходе перевод проекта на TypeScript не потребует остановки разработки и пройдёт без боли для всей команды.



Комментарии
0