ПрограммированиеBackend разработчик

Как описывать типы для сложных структур данных (например, вложенные объекты, массивы с разными типами) в TypeScript? Какие есть подходы и какие ловушки обычно встречаются? Приведите практические примеры.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Для описания сложных структур данных в TypeScript используют интерфейсы (interface) и псевдонимы типов (type). Можно комбинировать их с объектами, массивами и вложенными типами для строгой типизации сложных коллекций.

Для вложенного объекта:

interface Address { city: string; zip: number; } interface UserProfile { name: string; age: number; address: Address; }

Для массива с разными типами:

// Кортеж let tuple: [string, number] = ['John', 30]; // Массивы с union-типами let arr: (string | number)[] = [1, 'a', 2, 'b']; // Массив объектов let users: UserProfile[] = [ {...}, {...} ];

Когда структуры сложны и есть опциональные поля, используют ?, комбинируют с типами Partial, Record, Mapped Types, или рекурсивные типы для вложенных деревьев.

Вопрос с подвохом.

Вопрос: Можно ли использовать интерфейс для описания массива c разнотипными элементами (например, [string, number, boolean])?

Ответ: Нет. Для такого случая лучше использовать кортежи — интерфейсы не подходят для фиксированных позиций и типов. Кортежи позволяют строго задать типы по каждой позиции.

type MyTuple = [string, number, boolean]; let foo: MyTuple = ['ok', 12, false];

Примеры реальных ошибок из-за незнания тонкостей темы.


История

На проекте неправильно описали сложную структуру: для массива смешанных типов использовали any[] вместо корректного кортежа или union-типа. В результате, в одном из элементов оказалось значение не того типа, что привело к ошибке в бизнес-логике (арифметическая операция со строкой).


История

В структуре данных глубоко вложенные объекты были объявлены без использования рекурсивных типов или Partial. Попытка добавить к узлу дерева новое поддерево вызывала ошибку компилятора, и разработчики обходили это через downcast в any, что затем вызвало runtime-баги в продакшне.


История

Объект с описанием пользовательского профиля был частично опциональным, но разработчик не использовал ?. При получении данных с сервера TypeScript не ругался, а приложение падало, пытаясь обратиться к полям, которых не существовало в объекте.