TypeScript перед продакшеном: чек-лист для JS-разработчика
Проект собирается, типы вроде проставлены, но перед первым релизом всё равно тревожно. Разбираем, какие настройки tsconfig и приёмы стоит проверить, чтобы TypeScript ловил ошибки, а не создавал их.

Вы перевели JS-проект на TypeScript, код компилируется, IDE подсказывает типы — и кажется, что можно катить в прод. Проблема в том, что настройки по умолчанию у tsc мягкие: без явного включения строгих проверок компилятор пропустит null, где вы его не ждёте, и молча выведет any там, где вы думали, что тип известен. Ниже — что проверить в конфиге и коде до релиза, чтобы типы работали на вас. Материал актуален для TypeScript 5.x.
Что должно быть готово до проверки
Чек-лист рассчитан на проект, где уже есть tsconfig.json и код собирается хотя бы с ошибками-предупреждениями. Понадобится:
- Node.js 18 или новее и установленный TypeScript 5.x (
npx tsc --versionпокажет точную версию); - линтер —
@typescript-eslint, если проект на ESLint; - доступ к настройкам CI, чтобы прогонять проверку типов при сборке.
1. Включите strict целиком
Флаг strict в compilerOptions — это зонтик над группой проверок. Включённый strict: true активирует, среди прочего, strictNullChecks, noImplicitAny, strictFunctionTypes и strictPropertyInitialization. Без него компилятор пропустит целый класс ошибок, которые вы обнаружите уже в рантайме.
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}
Самая ценная из этих проверок — strictNullChecks. С ней null и undefined перестают быть допустимыми значениями для любого типа, и вы обязаны обработать их явно. Именно она отлавливает большинство падений вида «cannot read properties of undefined».
Если включить strict на большом проекте разом, вы получите сотни ошибок. Это не повод откатывать флаг — это карта мест, где код полагался на удачу.
На большой кодовой базе включайте не разом. Вариант — временно оставить strict: true, но добавить в проблемные файлы комментарий-послабление и разгребать по частям. Для миграции удобнее включать подфлаги по одному: сначала noImplicitAny, затем strictNullChecks.
2. Уберите any — явный и скрытый
Тип any отключает проверку типов для значения. Один any протекает по цепочке вызовов и обнуляет пользу TypeScript в целом куске кода. Различайте два источника.
Явный any вы пишете руками: let data: any. Замените на конкретный тип или, если тип действительно неизвестен, на unknown. Разница принципиальна: с unknown компилятор заставит сузить тип перед использованием, а с any — пропустит что угодно.
// плохо: any пропустит любое обращение
function parse(input: any) {
return input.value.toUpperCase(); // упадёт в рантайме, если value нет
}
// лучше: unknown требует проверки
function parseStrict(input: unknown) {
if (
typeof input === "object" &&
input !== null &&
"value" in input &&
typeof input.value === "string"
) {
return input.value.toUpperCase();
}
throw new Error("Неверный формат входных данных");
}
Скрытый any компилятор выводит сам, когда не может определить тип. Флаг noImplicitAny (входит в strict) превращает такие места в ошибки. Отдельно проверьте импорты внешних JS-библиотек без типов — они приходят как any. Для них ставьте пакеты @types/… или пишите свои .d.ts.
3. Не путайте проверку типов и сборку
Это ловушка, в которую попадают те, кто собирает проект через esbuild, swc или Vite. Эти сборщики выбрасывают типы, а не проверяют их — они компилируют TypeScript в JavaScript, игнорируя ошибки типов. Сборка проходит зелёной, а ошибка типа остаётся в коде.
Вывод: проверку типов надо запускать отдельной командой. Добавьте в package.json:
{
"scripts": {
"typecheck": "tsc --noEmit"
}
}
Флаг --noEmit велит компилятору проверить типы, но не генерировать файлы — сборкой занимается ваш быстрый сборщик, а tsc работает как чистый валидатор. Эту команду обязательно поставьте в CI отдельным шагом. Если её нет, типовые ошибки будут доезжать до прода.
4. Проверьте границы приложения
TypeScript проверяет типы только на этапе компиляции. В рантайме типов нет — остаётся обычный JavaScript. Это значит, что данные, которые приходят извне, компилятору не подконтрольны: ответ API, тело запроса, содержимое localStorage, переменные окружения, результат JSON.parse.
Опасный паттерн — приведение типа через as на границе:
// компилятор поверит на слово, а в ответе может быть что угодно
const user = (await response.json()) as User;
Здесь as User — обещание, которое компилятор не проверяет. Если сервер вернул другую структуру, вы получите ошибку глубоко внутри кода, где угодно, кроме места приведения. На границах приложения валидируйте данные в рантайме — например, через zod или valibot, которые одновременно проверяют значение и выводят тип из схемы.
5. Настройки, которые ловят реальные баги
Помимо strict есть несколько флагов, которые не входят в него, но заметно повышают безопасность. Включайте осознанно — каждый добавит ошибок компиляции.
| Флаг | Что ловит | Цена включения |
|---|---|---|
noUncheckedIndexedAccess | Обращение к массиву или объекту по индексу теперь даёт тип с undefined | Много новых проверок на undefined, но именно они частая причина падений |
exactOptionalPropertyTypes | Разделяет «свойство отсутствует» и «свойство равно undefined» | Может конфликтовать со сторонними типами |
noImplicitReturns | Функция, которая в одной ветке возвращает значение, а в другой нет | Низкая, находит реальные пропуски |
noFallthroughCasesInSwitch | Забытый break в switch | Низкая |
Флаг noUncheckedIndexedAccess недооценивают. Без него arr[0] имеет тип элемента, хотя массив может быть пустым. С ним тип становится «элемент или undefined», и компилятор заставит проверить. На проектах, где много работы с массивами и словарями, это отлавливает целый пласт ошибок.
6. Верните строгость линтеру
Некоторые вещи компилятор не считает ошибкой, но в проде они опасны. Их ловит @typescript-eslint. Полезные правила: no-floating-promises (промис без await или .catch — необработанное отклонение), no-misused-promises (промис там, где ждут булево значение), no-explicit-any. Правила, требующие информации о типах, включаются через конфигурацию с указанием parserOptions.project — проверьте это в актуальной документации typescript-eslint для вашей версии, синтаксис конфига менялся между мажорными релизами.
Если после включения strict всё красное
Типичные ошибки, которые вы увидите, и что с ними делать:
- «Object is possibly 'null'» / «possibly 'undefined'» — следствие
strictNullChecks. Не глушите оператором!(non-null assertion) везде подряд: он отключает проверку. Добавьте явную проверку или значение по умолчанию. - «Parameter 'x' implicitly has an 'any' type» —
noImplicitAnyнашёл параметр без типа. Проставьте тип или, для внешней библиотеки, поставьте пакет@types. - «Could not find a declaration file for module» — у импортированной JS-библиотеки нет типов. Ищите
@types/имя-пакеталибо создайте файл*.d.tsсdeclare module. - «Type 'X' is not assignable to type 'Y'» после включения
exactOptionalPropertyTypes— конфликт опциональных свойств. Часто проще выключить этот флаг, чем чинить типы сторонних пакетов.
Что дальше
После того как tsc --noEmit проходит чисто и стоит в CI, следующий шаг — зафиксировать это состояние: настройте pre-commit хук (например, через husky и lint-staged), чтобы проверка типов и линтер не давали закоммитить сломанный код. Отдельно посмотрите на время работы tsc на большом проекте: если проверка идёт минуты, включите инкрементальную компиляцию флагом incremental и разбейте монолит на проекты через references в tsconfig — это уже тема отдельного разбора про производительность сборки.
Тендерный специалист 44-ФЗ / 223-ФЗ: Разбор PDF-документации закупки, поиск «заточек» под поставщика, чек-лист заявки.
Спросить за 20 ₽Источники: TSConfig Reference — официальная документация TypeScript, typescript-eslint — правила и настройка
Частые вопросы
У меня TypeScript 4.x, а не 5.x — что-то из этого не сработает?
Включил strict, и проект перестал компилироваться сотнями ошибок. Что делать?
Можно ли просто везде ставить any, чтобы сборка прошла?
Сборка через Vite/esbuild проходит зелёной — значит, типы в порядке?
Нужен ли strictNullChecks, если я и так аккуратно пишу код?
Оператор ! (non-null assertion) — можно им глушить ошибки про null?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.