Использование TypeScript в связке с Express значительно повышает безопасность, масштабируемость и удобство поддержки серверных приложений. В данном руководстве Рэйчел, преподаватель платформы Scrimba и автор видео на канале freeCodeCamp.org, пошагово разбирает процесс создания типизированного API для приюта домашних животных.
🛠 Настройка окружения и установка зависимостей 2:08
Процесс начинается со стандартной инициализации Node.js проекта с помощью команды npm init -y . Для работы в среде TypeScript недостаточно просто установить Express; необходимо также добавить типы, так как сама библиотека написана на чистом JavaScript.
Для подготовки рабочего окружения автор устанавливает следующие пакеты:
- Express: основной фреймворк (устанавливается как обычная зависимость) .
- TypeScript: компилятор и инструменты языка (dev-dependency) .
- @types/express: определения типов для Express, позволяющие TypeScript понимать такие объекты, как
RequestиResponse. - tsconfig: специальный пакет с готовыми конфигурациями (в данном случае для Node 20) .
Конфигурация TypeScript осуществляется через файл tsconfig.json. Вместо ручного написания всех правил Рэйчел рекомендует расширять готовые пресеты с помощью поля extends . В compilerOptions критически важно указать:
rootDir: директорияsource, где будет храниться исходный код на TypeScript .outDir: директорияdist, куда компилятор будет помещать готовый JavaScript-код для запуска в Node.js .
🚀 Создание первого сервера и компиляция 7:12
Первый файл сервера создается с расширением .ts (например, index.ts). На этом этапе Рэйчел демонстрирует импорт типов напрямую из библиотеки: import express, { Express, Request, Response } from 'express' . Хотя TypeScript часто способен сам вывести типы (например, для экземпляра приложения app), явное указание типа Express помогает закрепить навыки работы с системой типов .
Поскольку Node.js не умеет исполнять TypeScript напрямую, код необходимо скомпилировать. Для этого используется встроенный компилятор npx tsc . Он анализирует проект и создает папку dist с JS-файлами. Только после этого сервер можно запустить командой node dist/index.js .
Чтобы упростить процесс разработки, Рэйчел предлагает настроить скрипты в package.json :
build: выполняетtsc.start: объединяет команды через оператор&&, сначала компилируя код, а затем запуская сервер (tsc && node dist/index.js) .
🐾 Моделирование данных и типизация сущностей 19:25
Для создания реального API требуется структура данных. В примере рассматривается приют для животных, где у каждого питомца есть набор характеристик. Автор переносит данные в отдельный файл source/data/pets.ts для соблюдения модульности .
Ключевым моментом здесь является создание кастомного типа Pet . В процессе разработки типа Рэйчел обращает внимание на использование специфических возможностей TypeScript:
- Optional properties: поля, помеченные вопросительным знаком (например,
adoptionDate?), так как не все животные в приюте уже обрели дом . - Union types: для поля
microchipId, которое может быть либо строкой, либоnull. - Вложенные объекты: для медицинских записей (
medicalRecord), содержащих массивы строк и числа .
🔍 Глубокая типизация Request и Response 33:01
Одной из самых мощных функций TypeScript в Express является использование дженериков (generics) для объектов запроса и ответа. Типы Request и Response позволяют точно описать, что именно сервер ожидает получить и что он отправит клиенту.
По словам Рэйчел, дженерик для Response позволяет задать структуру тела ответа (Response Body) . Например, если маршрут возвращает список животных, тип будет выглядеть как Response<Pet[]> . Это гарантирует, что разработчик не отправит ошибочные данные.
Объект Request еще более сложен и включает четыре основных параметра :
P: параметры пути (Path Params, например,:id).ResBody: тело ответа.ReqBody: тело запроса (для POST/PUT методов).ReqQuery: параметры строки запроса (Query Params).
🧪 Фильтрация и параметры запроса 41:31
Разработка функционала фильтрации (например, по виду животного или статусу адаптации) требует особого внимания к типам. Рэйчел подчеркивает, что параметры из req.query всегда приходят в виде строк . Если API должно фильтровать данные по булеву значению (adopted) или числу (age), эти значения необходимо парсить вручную.
Для удобства автор создает отдельный тип PetQueryParams, где описывает все возможные фильтры :
species: строка (например, "cat" или "dog").adopted: литеральный тип"true" | "false", что гораздо строже, чем простоstring.minAge/maxAge: строки, которые позже конвертируются в числа для сравнения .
🏗 Рефакторинг: Роутеры и Контроллеры 54:05
Когда файл index.ts становится слишком объемным («chunkier», как говорит Рэйчел), проект необходимо реструктурировать. Ведущая демонстрирует стандартный для Express подход разделения ответственности :
- Routes: определяют пути (endpoints) и используют
express.Router(). Здесь важно импортировать типRouterдля типизации самого объекта роутера . - Controllers: содержат бизнес-логику и обработчики. При переносе логики из роутера в контроллер необходимо также переносить и все связанные типы данных и запросов .
Такой подход делает код чистым и масштабируемым, сохраняя при этом полную типизацию всех связей.
🛡 Использование Middleware с TypeScript 1:03:13
Middleware (промежуточное ПО) — это функции, которые выполняются между получением запроса и отправкой ответа. В TypeScript для них предусмотрен специальный тип NextFunction .
Рэйчел приводит два практических примера кастомных middleware:
- Валидация ID: проверка, является ли переданный ID числом, с помощью регулярного выражения. Если проверка не проходит, сервер возвращает ошибку 400 еще до того, как запрос попадет в основной контроллер .
- Простая авторизация (
pleaseAuth): имитация проверки доступа, где пользователь обязан передать query-параметрpassword=please. В противном случае возвращается статус 401 (Unauthorized) .
В завершение курса Рэйчел отмечает, что хотя использование TypeScript добавляет «лишние шаги» (вроде установки типов для сторонних библиотек, таких как cors), это окупается за счет раннего обнаружения ошибок и автоматических подсказок в редакторе (Intellisense) .