Типизация ответов API
При работе с API в TypeScript важно не только получить данные, но и правильно описать их структуру. Это позволяет избежать ошибок на этапе разработки и сделать код более надёжным и читаемым.
Определение интерфейса ответа
Первый шаг — создать интерфейс, описывающий ожидаемую структуру данных от сервера. Например, если API возвращает информацию о пользователе:
interface User {
id: number;
name: string;
email: string;
}
Этот интерфейс можно использовать для типизации переменных, параметров функций и возвращаемых значений.
Приведение типа при получении данных
Метод response.json() возвращает промис с типом any, что отключает проверку типов. Чтобы восстановить безопасность, явно указывают ожидаемый тип:
const response = await fetch('/api/user/1');
const user: User = await response.json();
Теперь при обращении к user.name TypeScript знает, что это строка, а user.id — число. Если попытаться обратиться к несуществующему полю, например user.username, компилятор выдаст ошибку.
Почему типизация важна
Без типов легко допустить ошибку, особенно если структура ответа меняется или отличается от документации. Например, сервер может вернуть:
{ "id": 1, "username": "alex" }
а в коде ожидается:
interface User { name: string; }
Если не использовать типизацию, обращение к user.name завершится undefined, и ошибка проявится только во время выполнения. С интерфейсом TypeScript предупредит об этом ещё до запуска.
Безопасная обработка неизвестных данных
На практике нельзя полностью доверять серверу. Даже при наличии интерфейса реальный ответ может отличаться. Поэтому в production-коде рекомендуется сначала считать ответ типа unknown, а затем проверить его структуру.
Пример безопасного парсинга:
const response = await fetch('/api/user/1');
const rawData: unknown = await response.json();
if (
typeof rawData === 'object' &&
rawData !== null &&
'id' in rawData &&
'name' in rawData &&
typeof (rawData as any).id === 'number' &&
typeof (rawData as any).name === 'string'
) {
const user: User = rawData as User;
console.log(user.name);
} else {
throw new Error('Invalid user data received from server');
}
Такой подход называется проверкой времени выполнения (runtime validation). Он сочетается со статической типизацией и обеспечивает защиту как на этапе разработки, так и при работе приложения.
Для упрощения таких проверок в реальных проектах часто используют библиотеки вроде Zod или io-ts, но в рамках курса достаточно ручной проверки через условия и приведение типов.