# Строгий TypeScript на клиентских проектах: считаем, окупается ли

> Строгий режим замедляет старт и экономит на поддержке. Сравниваем два похожих проекта — со строгими типами и без — по числу правок после сдачи.

Адрес: https://egerpro.ru/blog/strogiy-typescript-na-proektah/
Обновлено: 2026-08-15

Строгий режим TypeScript — это лишние часы в начале проекта и меньше сюрпризов потом. Вопрос в том, окупается ли обмен на коротких проектах, где половина сайтов сдаётся за месяц.

## Что включает строгий режим

Флаг `strict` объединяет несколько проверок. Главные из них две: запрет неявного `any` и строгая проверка на `null` и `undefined`.

```
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}
```

Отдельно стоит `noUncheckedIndexedAccess`: он заставляет проверять результат обращения по индексу. Именно эта проверка ловит самый частый рантайм-баг — обращение к элементу пустого массива.

## Сравнение двух проектов

Два корпоративных сайта похожего объёма, сданы с разницей в четыре месяца, разные команды внутри студии. Первый — без строгого режима, второй — со строгим и дополнительными флагами.

- Время разработки: **19 дней против 23** — строгий режим добавил около 20%.
- Правки по багам за три месяца после сдачи: **14 против 4** .
- Из них связанных с отсутствующими данными: **9 против 0** .
- Суммарно время на поддержку: **21 час против 6** .

На дистанции в квартал строгий режим окупился примерно вдвое. На проекте, который сдали и забыли, он был бы чистым убытком — но таких проектов у нас почти нет: клиенты возвращаются с доработками.

## Где строгость мешает

### Данные из внешних источников

Ответ чужого API типизировать бессмысленно: реальность всё равно окажется другой. Мы валидируем такие данные на границе и внутрь пускаем уже проверенный объект.

```
import { z } from 'zod'

const OrderSchema = z.object({
  id: z.string(),
  total: z.number(),
  items: z.array(z.object({ sku: z.string(), qty: z.number() })),
})

// Дальше по коду тип известен и гарантирован
export function parseOrder(raw: unknown) {
  return OrderSchema.parse(raw)
}
```

### Быстрые прототипы

Если задача — показать клиенту идею за два дня, строгие типы только мешают. Прототип живёт в отдельной ветке и в продакшен не едет.

Компромисс, который работает

Включаем строгий режим на новом коде и оставляем послабления для старого: в `tsconfig` можно указать разные настройки для разных папок. Так не приходится останавливать разработку ради миграции.

## Как переводить существующий проект

1. Включаем `strict` и смотрим количество ошибок — обычно их сотни.
2. Не чиним всё сразу: добавляем `// @ts-expect-error` с комментарием и датой.
3. Каждую неделю разбираем часть помеченных мест.
4. Запрещаем добавлять новые подавления через правило линтера.

## Какие настройки дают эффект, а какие только шум

Строгий режим — это не одна галочка, а набор проверок, и они очень разные по отдаче. Главная — strictNullChecks: именно она ловит обращения к тому, чего может не быть, а это самый частый источник падений в браузере.

Дальше по полезности идёт noUncheckedIndexedAccess: обращение к элементу массива по индексу перестаёт считаться безопасным. Настройка раздражает первые дни и окупается на любом коде, который перебирает данные с сервера.

А вот noImplicitAny на существующем проекте лучше включать последним. Он даёт сотни ошибок сразу, и команда начинает расставлять any вместо типов — то есть делать ровно противоположное задуманному. Мы включаем его после того, как остальное уже зелёное.

## Где типы не окупаются

Короткие лендинги (посадочная страница) с двумя формами. Проект живёт месяц, кода мало, читать его повторно никто не будет — настройка окружения займёт больше времени, чем сэкономит.

Прототипы и эксперименты. Там ценна скорость проверки гипотезы, а типы заставляют оформлять то, что завтра выкинут. Мы прямо разделяем: прототип пишется свободно, а в продукт переносится уже с типами.

## Частые вопросы

**Сколько стоит перевод существующего проекта?**

По нашему опыту около 8–12% от объёма кодовой базы в человеко-часах, если переводить постепенно, файл за файлом. Разово и целиком — дороже и рискованнее: слишком много изменений в одном релизе (выпуск).

**Заменяет ли TypeScript тесты?**

Нет. Типы проверяют форму данных, тесты — поведение. Правильно посчитанная скидка неправильной формулой пройдёт проверку типов и не пройдёт тест. Одно без другого работает хуже.

Через два-три месяца проект оказывается полностью строгим, и никто не тратил на это отдельный спринт.
