TypeScript: быстрое погружение
Введение
TypeScript стоит изучать как рабочий инструмент, а не как список новых слов поверх JavaScript. В продукте он особенно заметен там, где раньше команда угадывала форму данных: ответ API, пропсы компонента, payload очереди, параметры функции, конфигурация окружения. Хороший тип не украшает код, а делает договоренность видимой для следующего разработчика.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 1 — первый контракт данных: src/contracts/payment.ts
Файл `src/contracts/payment.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: статус платежа ограничен тремя вариантами, а ошибка необязательна только там, где это реально допустимо.
Типичная ошибка: оставить status как обычный string и потерять подсказки редактора.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 2 — граница неизвестных данных: src/contracts/unknown-input.ts
Файл `src/contracts/unknown-input.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: данные из JSON сначала имеют тип unknown, а не доверенный интерфейс.
Типичная ошибка: сразу написать as PaymentDto и сделать вид, что внешние данные уже проверены.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 3 — минимальный сценарий запуска: package.json
Файл `package.json` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: в проекте есть отдельная проверка типов и отдельный запуск тестов.
Типичная ошибка: считать, что тесты заменяют typecheck, или наоборот.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Практический критерий всей книги простой: после каждого примера должно быть понятно, какой файл создать, какой код в нем лежит, что запустить и какую ошибку этот код предотвращает.
Глава 1: Установка и настройка TypeScript
Начинать проект лучше с локальной установки TypeScript и явного `tsconfig.json`. Глобальная установка удобна для быстрых экспериментов, но в команде она быстро создает расхождение версий: у одного разработчика код собирается, у другого падает, а CI живет третьей жизнью.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 4 — локальная установка: terminal
Файл `terminal` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: TypeScript установлен как dev-зависимость, а конфигурация создана в проекте.
Типичная ошибка: ставить компилятор глобально и не фиксировать версию в package.json.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 5 — строгий tsconfig для старта: tsconfig.json
Файл `tsconfig.json` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: включен strict-режим и проект проверяет только каталог src.
Типичная ошибка: отключать strict при первой сложной ошибке вместо постепенного исправления типов.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 6 — первый TypeScript-файл: src/index.ts
Файл `src/index.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: файл компилируется без ошибок и тип startedAt выводится автоматически.
Типичная ошибка: добавлять типы ко всему подряд, даже когда вывод типа очевиден.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 7 — скрипты проекта: package.json
Файл `package.json` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: typecheck можно запускать отдельно от сборки.
Типичная ошибка: смешивать проверку типов, сборку и запуск так, что непонятно, где именно ошибка.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 2: Базовые типы данных в TypeScript
Базовые типы — это первый слой честности. Они показывают, что значение является строкой, числом, флагом, массивом, объектом или ограниченным набором вариантов. Чем раньше команда перестает хранить важные состояния в свободных строках, тем меньше странных ошибок уходит в рантайм.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 8 — простые типы: src/basics/primitives.ts
Файл `src/basics/primitives.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: редактор знает тип каждого значения и предлагает методы для строк и массивов.
Типичная ошибка: писать string там, где допустимы только несколько конкретных строк.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 9 — union для статуса: src/basics/status.ts
Файл `src/basics/status.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: ошибка в статусе будет поймана до запуска.
Типичная ошибка: заменить TaskStatus на string и потерять смысл типа.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 10 — null как часть контракта: src/basics/nullable.ts
Файл `src/basics/nullable.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: перед чтением name код проверяет, что пользователь найден.
Типичная ошибка: вернуть null, но объявить результат как User.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 11 — readonly-массив: src/basics/readonly-array.ts
Файл `src/basics/readonly-array.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: функция обещает не менять массив тегов.
Типичная ошибка: передавать массив в функцию, которая случайно мутирует входные данные.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 3: Переменные и область видимости в TypeScript
В TypeScript переменные читаются через те же правила области видимости, что и в современном JavaScript. Разница в том, что типы помогают заметить, когда значение меняет форму слишком свободно. Новые проекты почти всегда стоит писать через `const` и `let`, оставляя `var` для чтения старого кода.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 12 — const и let: src/scope/let-const.ts
Файл `src/scope/let-const.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: userId нельзя переназначить, а attempts можно изменить явно.
Типичная ошибка: использовать let для значений, которые не должны меняться.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 13 — сужение в блоке: src/scope/narrowing.ts
Файл `src/scope/narrowing.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: внутри ветки TypeScript понимает конкретный тип value.
Типичная ошибка: пытаться вызвать строковый метод до проверки типа.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 14 — область видимости цикла: src/scope/loop.ts
Файл `src/scope/loop.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: переменная normalized живет только внутри цикла.
Типичная ошибка: выносить временные переменные наружу и случайно использовать старое значение.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 15 — явный тип для изменяемого состояния: src/scope/state.ts
Файл `src/scope/state.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: состояние меняется, но только в разрешенных границах.
Типичная ошибка: хранить состояние как произвольную строку.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 4: Функции в TypeScript
Функция — это маленький контракт. Входные параметры показывают, что можно передать, возвращаемый тип показывает, что получит вызывающий код. В команде хорошая сигнатура функции часто экономит больше времени, чем длинный комментарий.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 16 — параметры и результат: src/functions/format-price.ts
Файл `src/functions/format-price.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: валюта ограничена разрешенными значениями.
Типичная ошибка: принимать currency как string и ловить опечатки только глазами.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 17 — объект параметров: src/functions/create-user.ts
Файл `src/functions/create-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: входной объект описан одним типом и его можно переиспользовать.
Типичная ошибка: передавать много позиционных параметров и путать их порядок.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 18 — перегрузка не всегда нужна: src/functions/normalize.ts
Файл `src/functions/normalize.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: простого union достаточно для двух близких входов.
Типичная ошибка: делать сложные overloads там, где обычный union читается лучше.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 19 — функция высшего порядка: src/functions/filter-by.ts
Файл `src/functions/filter-by.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тип item выводится из массива автоматически.
Типичная ошибка: объявлять predicate как Function и потерять тип аргумента.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 5: Интерфейсы в TypeScript
Интерфейс полезен там, где нужно описать форму объекта и договориться о ней между частями приложения. Это особенно видно на границах: компонент ждет пропсы, сервис ждет DTO, функция получает настройки.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 20 — модель пользователя: src/interfaces/user.ts
Файл `src/interfaces/user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: email явно необязателен, и код это учитывает.
Типичная ошибка: писать email: string, а потом передавать объекты без email.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 21 — расширение интерфейса: src/interfaces/admin.ts
Файл `src/interfaces/admin.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: AdminProfile содержит поля пользователя и свои разрешения.
Типичная ошибка: копировать одинаковые поля в нескольких интерфейсах.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 22 — интерфейс сервиса: src/interfaces/repository.ts
Файл `src/interfaces/repository.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: код зависит от контракта, а не от конкретной базы данных.
Типичная ошибка: привязать функцию к конкретной реализации и усложнить тесты.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 23 — type или interface: src/interfaces/type-vs-interface.ts
Файл `src/interfaces/type-vs-interface.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: interface удобен для объекта, type — для alias и union.
Типичная ошибка: спорить о стиле вместо выбора читаемой формы для конкретной задачи.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 6: Классы и объектно-ориентированное программирование в TypeScript
Классы полезны там, где состояние и поведение действительно живут вместе. Но TypeScript не требует писать все через классы. Иногда функция и интерфейс проще; иногда класс делает зависимость явной и удобной для тестирования.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 24 — класс с приватным состоянием: src/classes/counter.ts
Файл `src/classes/counter.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: счетчик меняется только через методы класса.
Типичная ошибка: делать публичным состояние, которое нельзя менять напрямую.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 25 — конструктор и readonly: src/classes/api-client.ts
Файл `src/classes/api-client.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: baseUrl задается один раз и дальше не переназначается.
Типичная ошибка: менять конфигурацию клиента в случайном месте.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 26 — реализация интерфейса: src/classes/memory-store.ts
Файл `src/classes/memory-store.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: класс обещает соответствовать интерфейсу Store.
Типичная ошибка: переименовать метод и не заметить, что контракт сломан.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 27 — композиция вместо наследования: src/classes/logger.ts
Файл `src/classes/logger.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: сервис получает зависимость явно через конструктор.
Типичная ошибка: строить глубокую иерархию наследования ради простого логирования.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 7: Генерики в TypeScript
Генерики нужны, когда функция, класс или интерфейс работают с разными типами, но должны сохранить связь между входом и выходом. Это не “сложные скобки”, а способ не потерять информацию о типе.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 28 — первый элемент массива: src/generics/first.ts
Файл `src/generics/first.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: результат связан с типом элементов массива.
Типичная ошибка: вернуть any и заставить вызывающий код гадать.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 29 — обертка результата: src/generics/result.ts
Файл `src/generics/result.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: Result хранит разные данные, но одинаковую форму успеха/ошибки.
Типичная ошибка: делать data необязательным и error необязательным в одном объекте.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 30 — ограничение generic: src/generics/constraints.ts
Файл `src/generics/constraints.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: функция принимает только объекты с id.
Типичная ошибка: читать item.id у произвольного T без ограничения.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 31 — generic-компонент данных: src/generics/page.ts
Файл `src/generics/page.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: одна форма страницы подходит разным сущностям.
Типичная ошибка: копировать PageUsers, PageOrders, PageTasks вручную.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 32 — значение по умолчанию: src/generics/default.ts
Файл `src/generics/default.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: если тип не указан, данные остаются unknown.
Типичная ошибка: ставить any по умолчанию и выключать безопасность.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 8: Модули и пространства имен в TypeScript
Модули позволяют разложить проект на понятные файлы. В современной TypeScript-разработке почти всегда стоит использовать `import` и `export`; пространства имен в основном встречаются в старом коде и декларациях.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 33 — экспорт типа: src/modules/user.ts
Файл `src/modules/user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тип и функция импортируются из одного модуля.
Типичная ошибка: держать общие типы в случайных файлах без понятного экспорта.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 34 — type-only import: src/modules/app.ts
Файл `src/modules/app.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: импорт типа отделен от импорта runtime-функции.
Типичная ошибка: тащить runtime-import ради типа там, где он не нужен.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 35 — index barrel: src/modules/index.ts
Файл `src/modules/index.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: модульная граница собрана в одном публичном файле.
Типичная ошибка: экспортировать весь внутренний хаос наружу.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 9: Расширенные типы данных в TypeScript
Расширенные типы помогают описывать состояния и границы данных. Самое полезное здесь — union, intersection, literal-типы и type guards. Они делают модель точнее без лишней магии.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 36 — discriminated union: src/advanced/load-state.ts
Файл `src/advanced/load-state.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: ветка ready открывает доступ к data.
Типичная ошибка: делать data? и message? в одном рыхлом объекте.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 37 — intersection для роли: src/advanced/intersection.ts
Файл `src/advanced/intersection.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: Admin обязан иметь поля обоих типов.
Типичная ошибка: использовать intersection для несовместимых моделей.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 38 — type guard: src/advanced/guard.ts
Файл `src/advanced/guard.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: unknown становится ApiUser только после проверки.
Типичная ошибка: верить внешнему JSON без проверки.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 39 — never для полноты: src/advanced/exhaustive.ts
Файл `src/advanced/exhaustive.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: при добавлении нового статуса компилятор потребует обновить switch.
Типичная ошибка: оставить default без проверки never и пропустить новую ветку.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 10: Типизация и проверка значений с помощью TypeScript Utility Types
Utility Types помогают собирать производные модели без ручного копирования. Они особенно полезны там, где одна сущность живет в разных формах: создание, обновление, публичный ответ, словарь.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 40 — модели создания и обновления: src/utility/user-inputs.ts
Файл `src/utility/user-inputs.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: из одной модели собраны три рабочих контракта.
Типичная ошибка: писать почти одинаковые интерфейсы и забывать обновлять один из них.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 41 — Record для словаря: src/utility/record.ts
Файл `src/utility/record.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: словарь обязан иметь все ключи Locale.
Типичная ошибка: использовать объект без контроля обязательных ключей.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 42 — Readonly для настроек: src/utility/readonly.ts
Файл `src/utility/readonly.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: код не может случайно переназначить поле config.
Типичная ошибка: считать комментарий “не менять” достаточной защитой.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 43 — Exclude и Extract: src/utility/exclude-extract.ts
Файл `src/utility/exclude-extract.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тип события уточняется без ручного перечисления копий.
Типичная ошибка: плодить похожие union-типы руками.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 11: Асинхронное программирование и работа с промисами в TypeScript
Асинхронный код чаще всего ломается на границах: сеть вернула ошибку, данные отсутствуют, параллельные запросы пришли не в том порядке. TypeScript помогает описать результат, но не отменяет обработку ошибок.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 44 — async-функция с null: src/async/load-user.ts
Файл `src/async/load-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: вызывающий код обязан обработать null.
Типичная ошибка: объявить Promise<User>, хотя пользователь может не существовать.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 45 — Promise.all: src/async/dashboard.ts
Файл `src/async/dashboard.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: параллельные запросы дают типизированный объект результата.
Типичная ошибка: запускать независимые запросы последовательно без причины.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 46 — Result вместо throw: src/async/result.ts
Файл `src/async/result.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: ошибка становится частью типа результата.
Типичная ошибка: смешивать исключения и nullable-результаты без понятного правила.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 47 — AbortController: src/async/abort.ts
Файл `src/async/abort.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: запрос можно отменить по таймауту.
Типичная ошибка: оставлять долгие запросы без отмены в UI.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 12: Декораторы в TypeScript
Декораторы часто встречаются во фреймворках: NestJS, TypeORM, class-validator. Они удобны, когда инфраструктура читает метаданные и строит поведение вокруг класса. Но в обычном коде декоратор может спрятать слишком много магии.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 48 — метод с логированием: src/decorators/log.ts
Файл `src/decorators/log.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: понятно, что декоратор оборачивает метод.
Типичная ошибка: использовать декораторы там, где обычная функция-обертка проще.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 49 — DTO с декораторами: src/decorators/create-user.dto.ts
Файл `src/decorators/create-user.dto.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: DTO показывает правила валидации рядом с полями.
Типичная ошибка: забыть, что декоратор работает только при подключенной runtime-библиотеке.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 50 — без декоратора: src/decorators/plain.ts
Файл `src/decorators/plain.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: иногда явная функция понятнее декоратора.
Типичная ошибка: выбирать синтаксическую красоту вместо читаемости.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 13: Работа с типами данных в TypeScript — продвинутые возможности
Продвинутые типы нужны, когда простая модель начинает повторяться или терять ограничения. Главный принцип: тип должен ловить реальную ошибку, а не демонстрировать мастерство автора.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 51 — mapped type для ошибок формы: src/types/form-errors.ts
Файл `src/types/form-errors.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: ключи ошибок совпадают с ключами формы.
Типичная ошибка: хранить ошибки как Record<string, string> и терять связь с формой.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 52 — conditional type: src/types/async-value.ts
Файл `src/types/async-value.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тип извлекает значение из Promise.
Типичная ошибка: писать условный тип там, где достаточно готового Awaited<T>.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 53 — template literal type: src/types/events.ts
Файл `src/types/events.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: имя события строится из разрешенных частей.
Типичная ошибка: оставить событие свободной строкой.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 54 — ключи объекта: src/types/get-field.ts
Файл `src/types/get-field.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: key может быть только реальным ключом объекта.
Типичная ошибка: принимать key как string и получать undefined в рантайме.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 14: Работа с модулями Node.js в TypeScript
На backend TypeScript быстрее всего окупается на DTO, конфигурации и обработчиках запросов. Серверный код часто работает с внешними данными, поэтому типы должны показывать, где данные уже проверены, а где еще нет.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 55 — DTO для задачи: src/node/create-task.dto.ts
Файл `src/node/create-task.dto.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: входные данные отделены от внутренней модели Task.
Типичная ошибка: принимать любой объект из request.body как готовую задачу.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 56 — service-функция: src/node/task-service.ts
Файл `src/node/task-service.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: сервис нормализует данные и создает системные поля сам.
Типичная ошибка: позволять клиенту прислать id и done.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 57 — Express-style handler: src/node/handler.ts
Файл `src/node/handler.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: handler не доверяет body до проверки.
Типичная ошибка: типизировать body как CreateTaskDto без runtime-проверки.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 58 — env reader: src/node/env.ts
Файл `src/node/env.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: ошибка конфигурации всплывает при старте.
Типичная ошибка: читать process.env напрямую по всему приложению.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 15: Тестирование TypeScript-кода
Тестовая глава должна быть маленьким рабочим проектом, а не обещанием примеров без самих примеров. Здесь основной стек — Vitest. Он хорошо подходит современным TypeScript/Vite-проектам, быстро запускается и позволяет писать тесты рядом с кодом. TypeScript при этом проверяет типы отдельно: тесты не заменяют `tsc --noEmit`.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 59 — package для тестов: package.json
Файл `package.json` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: есть отдельные команды для тестов, watch-режима и проверки типов.
Типичная ошибка: считать успешный vitest run полной проверкой типов проекта.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 60 — tsconfig для Vitest: tsconfig.json
Файл `tsconfig.json` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: TypeScript понимает тестовые файлы и strict-режим.
Типичная ошибка: оставить тесты вне include и удивляться пропущенным ошибкам.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 61 — функция для тестирования: src/math.ts
Файл `src/math.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: функции экспортированы и имеют явные типы результата.
Типичная ошибка: держать функцию внутри теста и не проверять реальный модуль.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 62 — первый тест: src/math.test.ts
Файл `src/math.test.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тест импортирует реальную функцию из src/math.ts.
Типичная ошибка: обещать файл, но не показывать его содержимое целиком.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 63 — table-driven тест: src/math-table.test.ts
Файл `src/math-table.test.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: несколько случаев проверяются одним шаблоном.
Типичная ошибка: копировать пять одинаковых тестов и менять только числа.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 64 — проверка исключения: src/divide.test.ts
Файл `src/divide.test.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: ошибка проверяется как поведение функции.
Типичная ошибка: вызывать divide(10, 0) до expect и падать вне проверки.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 65 — асинхронная функция: src/user-api.ts
Файл `src/user-api.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: зависимость fetcher передается явно, поэтому ее легко заменить в тесте.
Типичная ошибка: вшить global fetch и усложнить тестирование.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 66 — async-тест: src/user-api.test.ts
Файл `src/user-api.test.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тест ждет Promise и проверяет результат.
Типичная ошибка: забыть await и получить ложноположительный тест.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 67 — fake dependency: src/email-service.ts
Файл `src/email-service.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: сервис зависит от интерфейса Mailer, а не от внешней почты.
Типичная ошибка: в тесте реально отправлять письмо.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 68 — mock через vi.fn: src/email-service.test.ts
Файл `src/email-service.test.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: mock проверяет вызов зависимости без реальной интеграции.
Типичная ошибка: мокать все подряд и перестать проверять важное поведение.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 69 — команды запуска: terminal
Файл `terminal` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: сначала проходит проверка типов, потом тесты.
Типичная ошибка: лечить ошибку типов изменением теста вместо исправления контракта.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
После такой главы у читателя есть не абстрактное “тестирование полезно”, а минимальный проект: конфигурация, тестируемая функция, обычный тест, параметризованный тест, исключения, async, fake dependency и mock. Это тот минимум, с которого уже можно перенести практику в рабочий репозиторий.
Глава 16: TypeScript и React
В React типы должны находиться рядом с UI-договоренностями: пропсы, состояния загрузки, события формы, данные из API. Если компонент может быть в нескольких состояниях, это лучше показать union-типом, а не набором случайных флагов.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 70 — проект Vite React TS: terminal
Файл `terminal` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: проект создается сразу с .tsx и TypeScript-конфигурацией.
Типичная ошибка: начать с JS-шаблона, а потом хаотично мигрировать все файлы.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 71 — типизированные пропсы: src/components/Button.tsx
Файл `src/components/Button.tsx` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: компонент явно говорит, что ему нужно.
Типичная ошибка: описать props как any ради скорости.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 72 — состояние загрузки: src/components/UserCard.tsx
Файл `src/components/UserCard.tsx` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: UI-состояния являются частью типа.
Типичная ошибка: держать loading, error и user отдельными несогласованными пропсами.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 73 — форма: src/components/ProfileForm.tsx
Файл `src/components/ProfileForm.tsx` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: форма хранит ввод пользователя как строки.
Типичная ошибка: сразу превращать age в number и ломать пустое поле.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 17: Работа с Redux и TypeScript
Redux имеет смысл типизировать через состояние, action creators и selectors. Не нужно писать типы ради церемонии: цель в том, чтобы payload событий и shape состояния не расходились.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 74 — slice state: src/store/tasks.types.ts
Файл `src/store/tasks.types.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: состояние задач описано явно.
Типичная ошибка: хранить selectedId как string и забыть про отсутствие выбора.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 75 — action union: src/store/tasks.actions.ts
Файл `src/store/tasks.actions.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: payload каждого action отличается и проверяется.
Типичная ошибка: описать action как { type: string; payload: any }.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 76 — reducer: src/store/tasks.reducer.ts
Файл `src/store/tasks.reducer.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: в каждой ветке action.payload имеет нужную форму.
Типичная ошибка: проверять payload вручную в reducer.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 18: Работа с GraphQL и TypeScript
GraphQL уже описывает контракт API, а TypeScript помогает принести этот контракт в клиентский код. Даже без генерации типов полезно явно описывать форму query result и variables.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 77 — query result: src/graphql/types.ts
Файл `src/graphql/types.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: nullable-поля GraphQL явно видны в TypeScript.
Типичная ошибка: считать email всегда строкой, хотя схема разрешает null.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 78 — typed request: src/graphql/request.ts
Файл `src/graphql/request.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: функция связывает тип результата и переменных с конкретным вызовом.
Типичная ошибка: возвращать Promise<any> и терять смысл схемы.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 79 — query usage: src/graphql/load-user.ts
Файл `src/graphql/load-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: переменные query проверяются TypeScript.
Типичная ошибка: передать в variables объект без id.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 19: Работа с MongoDB и TypeScript
MongoDB гибкая, но приложение все равно должно знать свои документы. Типы помогают описать документ, вход для создания и результат чтения, особенно когда старые документы могут иметь неполные поля.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 80 — document type: src/mongo/user-document.ts
Файл `src/mongo/user-document.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: документ базы отделен от публичного DTO.
Типичная ошибка: отдавать _id наружу без явного преобразования.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 81 — insert input: src/mongo/create-user.ts
Файл `src/mongo/create-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: сервер сам создает технические поля.
Типичная ошибка: принимать _id от клиента.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 82 — public dto: src/mongo/public-user.ts
Файл `src/mongo/public-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: публичная модель не совпадает слепо с документом базы.
Типичная ошибка: возвращать документ базы прямо в API.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 20: Работа с WebSocket и TypeScript
WebSocket-сообщения должны быть типизированы как события. Иначе проект быстро получает набор строк, которые нельзя безопасно переименовать и сложно проверить.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 83 — event union: src/socket/events.ts
Файл `src/socket/events.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: каждое событие имеет свой payload.
Типичная ошибка: отправлять { type: string; payload: unknown } без проверки.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 84 — send helper: src/socket/send.ts
Файл `src/socket/send.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: наружу уходит только допустимое событие.
Типичная ошибка: собирать JSON руками в разных местах.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 85 — event handler: src/socket/handle.ts
Файл `src/socket/handle.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: switch сужает тип payload.
Типичная ошибка: читать event.text у любого события.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 21: Интеграция TypeScript с Docker
Docker нужен не ради моды, а ради одинаковой среды сборки. Для TypeScript-проекта важно разделять установку зависимостей, проверку типов, сборку и запуск уже собранного JavaScript.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 86 — Dockerfile: Dockerfile
Файл `Dockerfile` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: образ собирает проект и запускает только dist.
Типичная ошибка: запускать ts-node в production без необходимости.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 87 — dockerignore: .dockerignore
Файл `.dockerignore` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: в образ не попадают локальные артефакты и секреты.
Типичная ошибка: копировать node_modules с машины разработчика.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 88 — compose для разработки: docker-compose.yml
Файл `docker-compose.yml` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: контейнер можно поднять одинаково на машине и в CI.
Типичная ошибка: держать переменные окружения только в устной инструкции.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 22: CI/CD для TypeScript-проектов с использованием GitHub Actions
CI — это автоматическая договоренность команды о минимальном качестве. Если типы не проходят, тесты падают или проект не собирается, код не должен попадать в main.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 89 — workflow check: .github/workflows/check.yml
Файл `.github/workflows/check.yml` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: CI гоняет типы, тесты и сборку.
Типичная ошибка: оставить проверку типов только локальной привычкой.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 90 — package scripts: package.json
Файл `package.json` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: workflow вызывает понятные npm-скрипты.
Типичная ошибка: писать длинные команды прямо в YAML и дублировать их локально.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 91 — pull request gate: .github/pull_request_template.md
Файл `.github/pull_request_template.md` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: команда видит критерии готовности до ревью.
Типичная ошибка: полагаться только на память ревьюера.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 23: Типы и безопасность данных в TypeScript
TypeScript не проверяет внешние данные в рантайме. Все, что пришло из формы, сети, файла, очереди или переменных окружения, нужно считать недоверенным до проверки.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 92 — unsafe boundary: src/security/input.ts
Файл `src/security/input.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: граница возвращает unknown, а не готовый DTO.
Типичная ошибка: объявить JSON.parse как CreateUserDto.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 93 — ручная проверка: src/security/is-create-user.ts
Файл `src/security/is-create-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тип сужается после проверки.
Типичная ошибка: проверить только наличие объекта и забыть поля.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 94 — санитизация вывода: src/security/public-user.ts
Файл `src/security/public-user.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: секретное поле не попадает в публичный ответ.
Типичная ошибка: возвращать user целиком и надеяться, что клиент не заметит лишнего.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 24: Реализация CQRS и Event Sourcing с TypeScript
CQRS и Event Sourcing полезны не в каждом проекте. Их стоит применять там, где история изменений действительно важна. TypeScript помогает описать команды, события и read model как разные контракты.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 95 — commands: src/cqrs/commands.ts
Файл `src/cqrs/commands.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: команды описывают намерение изменить систему.
Типичная ошибка: смешивать команды и события в одном типе.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 96 — events: src/cqrs/events.ts
Файл `src/cqrs/events.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: события описывают уже случившийся факт.
Типичная ошибка: называть событие в будущем времени.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 97 — projector: src/cqrs/projector.ts
Файл `src/cqrs/projector.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: read model строится из событий.
Типичная ошибка: обновлять read model без понимания последовательности событий.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 25: Использование TypeORM с TypeScript для работы с реляционными базами данных
ORM удобен, но типы сущностей не заменяют понимание базы. Важно отдельно видеть entity, input DTO и транзакционные операции.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 98 — entity: src/typeorm/user.entity.ts
Файл `src/typeorm/user.entity.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: nullable в базе отражен в типе.
Типичная ошибка: описать email как string и забыть про null.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 99 — input dto: src/typeorm/create-user.dto.ts
Файл `src/typeorm/create-user.dto.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: DTO не содержит id и служебные поля.
Типичная ошибка: принимать entity как вход API.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 100 — repository use: src/typeorm/user.service.ts
Файл `src/typeorm/user.service.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: сервис управляет преобразованием DTO в entity.
Типичная ошибка: раскидать users.save по контроллерам.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 26: Реализация микросервисов с TypeScript и NestJS
NestJS дает понятную структуру, но границы все равно нужно проектировать. Контроллер принимает запрос, DTO описывает вход, сервис держит логику, а модуль собирает зависимости.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 101 — DTO: src/nest/create-task.dto.ts
Файл `src/nest/create-task.dto.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: DTO является явной формой входа.
Типичная ошибка: принимать any в controller ради скорости.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 102 — service: src/nest/tasks.service.ts
Файл `src/nest/tasks.service.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: логика создания находится в service.
Типичная ошибка: класть бизнес-логику в controller.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 103 — controller: src/nest/tasks.controller.ts
Файл `src/nest/tasks.controller.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: controller тонкий и делегирует работу сервису.
Типичная ошибка: делать controller местом всей логики.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 27: Поддержка многопоточности и фоновых задач в TypeScript с использованием Bull и Redis
Очередь задач нужна там, где действие не должно блокировать пользовательский запрос: отправка письма, обработка файла, пересчет отчета. TypeScript помогает синхронизировать payload между producer и worker.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 104 — job payload: src/jobs/email-job.ts
Файл `src/jobs/email-job.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: producer и worker используют один тип payload.
Типичная ошибка: передавать в очередь произвольный объект.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 105 — producer: src/jobs/producer.ts
Файл `src/jobs/producer.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: код не даст отправить неизвестный template.
Типичная ошибка: зашить строку template без типа.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 106 — worker: src/jobs/worker.ts
Файл `src/jobs/worker.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: worker получает уже ожидаемую форму данных.
Типичная ошибка: читать job.data.to без типа.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 28: Обработка и трансформация данных с использованием RxJS в TypeScript
RxJS полезен для потоков событий, но его стоит вводить осознанно. Типы помогают не потерять форму данных в цепочке операторов.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 107 — stream type: src/rxjs/events.ts
Файл `src/rxjs/events.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: поток знает тип элементов.
Типичная ошибка: использовать Observable<any>.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 108 — map/filter: src/rxjs/pipeline.ts
Файл `src/rxjs/pipeline.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: после map поток становится строковым.
Типичная ошибка: терять тип между операторами.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 109 — typed command stream: src/rxjs/commands.ts
Файл `src/rxjs/commands.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: union работает и внутри RxJS pipeline.
Типичная ошибка: передавать команды как строки без payload.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 29: Оптимизация производительности TypeScript-приложений
Производительность TypeScript-проекта — это не только рантайм. Есть скорость сборки, скорость проверки типов, размер бандла и читаемость типов. Иногда самый быстрый код для команды — тот, который проще безопасно менять.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 110 — измерение времени: src/perf/measure.ts
Файл `src/perf/measure.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: измерение обернуто типизированной функцией.
Типичная ошибка: оптимизировать без измерений.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 111 — lazy import: src/perf/lazy.ts
Файл `src/perf/lazy.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: тяжелый модуль загружается по требованию.
Типичная ошибка: тащить весь admin-код в стартовый бандл.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 112 — простая модель вместо сложного типа: src/perf/simple-type.ts
Файл `src/perf/simple-type.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: модель проста и не тормозит понимание.
Типичная ошибка: строить огромный conditional type ради простой строки.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Глава 30: Интеграция TypeScript с AWS для создания серверных приложений
В AWS TypeScript часто используют для Lambda, SDK-клиентов и CDK. Самые частые ошибки происходят на конфигурации и форме события, поэтому начните с env и handler-контрактов.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 113 — env reader: src/aws/env.ts
Файл `src/aws/env.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: Lambda падает рано, если переменная окружения не задана.
Типичная ошибка: читать process.env.USERS_TABLE в каждом файле.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 114 — lambda event: src/aws/handler.ts
Файл `src/aws/handler.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: handler явно обрабатывает отсутствие id.
Типичная ошибка: считать pathParameters.id всегда существующим.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 115 — typed S3 call: src/aws/s3.ts
Файл `src/aws/s3.ts` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: обертка фиксирует формат JSON-записи.
Типичная ошибка: размазывать параметры S3 по приложению.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Заключение: как продолжать после быстрого погружения
TypeScript становится полезным не тогда, когда в проекте много угловых скобок, а когда команда меньше угадывает. После этой книги у вас должны остаться не только термины, но и набор файловых шаблонов: тип DTO, type guard, React-пропсы, Vitest-тест, Dockerfile, CI workflow, env reader.
В этой главе код идет рядом с объяснением. Сначала смотрите на имя файла, потом на контракт, который код фиксирует, и только после этого на синтаксис. Такой порядок ближе к реальной разработке: мы пишем не “пример ради примера”, а маленькую проверяемую договоренность.
Листинг 116 — аудит первого участка: docs/type-audit.md
Файл `docs/type-audit.md` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: есть практический маршрут после чтения.
Типичная ошибка: закрыть книгу и пытаться “типизировать все” без приоритета.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 117 — definition of done для типов: docs/dod.md
Файл `docs/dod.md` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: типизация становится частью командной готовности.
Типичная ошибка: считать TypeScript личным стилем одного разработчика.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Листинг 118 — план миграции: docs/migration-plan.md
Файл `docs/migration-plan.md` нужен не как абстрактная вставка, а как маленький рабочий кусок проекта. Перед чтением кода обратите внимание на границу ответственности: что этот файл принимает на вход, что возвращает наружу и какая договоренность становится видимой для TypeScript. Именно так программист читает пример в реальном репозитории.
Что проверить: переход разбит на спокойные шаги.
Типичная ошибка: устроить большой переписывательный пожар.
Как читать этот листинг: сначала найдите публичные имена — exported types, functions или classes. Затем посмотрите, где TypeScript ограничивает значения, а где код все еще обязан проверять данные в рантайме. Такой разбор важнее механического переписывания: он показывает, какую категорию ошибок пример должен убрать из проекта.
Если переносите пример в свой код, не копируйте имена слепо. Сохраните принцип: явная граница, узкий тип, понятная ошибка и короткий путь проверки. Тогда пример останется полезным даже в проекте с другой архитектурой, фреймворком или сборщиком.
После листинга полезно вслух сформулировать, какую ошибку теперь поймает TypeScript и что останется проверять тестами или рантайм-валидацией. Это простая привычка, но она быстро отделяет полезную типизацию от декоративной.
Главное правило простое: тип должен объяснять намерение и снижать риск изменения. Если тип усложняет жизнь, но не ловит реальную ошибку, его нужно упростить. Если тип помогает следующему разработчику безопасно продолжить работу, он уже окупился.
Условия публичной лицензии для электронных версий
Автор и правообладатель разрешает следующие виды использования данного файла, являющегося электронным представлением Произведения, без уведомления правообладателя и без выплаты авторского вознаграждения: Воспроизведение Произведения (полностью или частично) на бумаге путём распечатки с помощью принтера в одном экземпляре для удовлетворения личных бытовых или учебных потребностей; Копирование и распространение данного файла в электронном виде, в том числе путём записи на физические носители и путём передачи по компьютерным сетям, с соблюдением следующих условий: все воспроизведённые и передаваемые любым лицам экземпляры файла являются точными копиями исходного файла в формате PDF, при копировании не производится никаких изъятий, сокращений, дополнений, искажений и любых других изменений, включая и изменение формата представления файла; распространение и передача копий другим лицам производится исключительно бесплатно, то есть при передаче не взимается никакое вознаграждение ни в какой форме, в том числе в форме просмотра рекламы, в форме платы за носитель или за сам акт копирования и передачи, даже если такая плата оказывается значительно меньше фактической стоимости или себестоимости носителя, акта копирования и т.п. Любые другие способы распространения данного файла при отсутствии письменного разрешения автора запрещены. В частности, запрещается: внесение каких-либо изменений в данный файл, создание и распространение искаженных экземпляров, в том числе экземпляров, содержащих какую-либо часть произведения; Разрешается дарение (бесплатная передача) носителей, содержащих данный файл, запись данного файла на носители, принадлежащие другим пользователям, распространение данного файла через бесплатные файлообменные сети и т.п.
Спасибо за чтение
Вернуться к книге
