Короткий ответ: сначала опишите тип одного объекта, а затем укажите массив этого типа: User[] или Array<User>. TypeScript будет проверять каждый элемент массива: обязательные поля, типы значений, optional-поля и ошибки в названиях ключей
Простой пример:
type User = {
id: number;
name: string;
email: string;
};
const users: User[] = [
{ id: 1, name: "Dinar", email: "dinar@example.com" },
{ id: 2, name: "Anna", email: "anna@example.com" },
];
Если во втором объекте забыть email, TypeScript покажет ошибку
Через interface
interface Product {
id: number;
title: string;
price: number;
}
const products: Product[] = [
{ id: 1, title: "Книга", price: 900 },
{ id: 2, title: "Курс", price: 5000 },
];
Для массива объектов разницы между type и interface почти нет. Выбирайте стиль, который уже используется в проекте
Синтаксис Array<T>
const products: Array<Product> = [
{ id: 1, title: "Книга", price: 900 },
];
Product[] и Array<Product> означают одно и то же. В обычных объектах часто используют короткую запись Product[]
Optional поля
type Article = {
id: number;
title: string;
description?: string;
};
const articles: Article[] = [
{ id: 1, title: "TypeScript" },
{ id: 2, title: "React", description: "Про компоненты" },
];
При чтении optional-поля проверяйте наличие:
articles.forEach((article) => {
console.log(article.description?.toUpperCase());
});
Массив из API
Частый сценарий:
type UserDto = {
id: number;
name: string;
};
async function loadUsers(): Promise<UserDto[]> {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error("Failed to load users");
}
return response.json() as Promise<UserDto[]>;
}
Важно понимать: as Promise<UserDto[]> не валидирует данные в runtime. Это только подсказка TypeScript. Если API может вернуть мусор, добавьте runtime-проверку или схему валидации
map, filter и reduce
Когда массив типизирован, методы массива получают тип автоматически:
const names = users.map((user) => user.name);
names будет string[]
Фильтрация:
const paidUsers = users.filter((user) => user.email.endsWith("@example.com"));
TypeScript знает, что user внутри callback — это User
readonly массив
Если функцию не нужно менять массив:
function printUsers(users: readonly User[]) {
users.forEach((user) => console.log(user.name));
}
Так внутри функции нельзя случайно сделать users.push(...)
Частые ошибки
Первая ошибка — писать object[]. Такой тип почти ничего не говорит о полях
Вторая ошибка — использовать any[]. Тогда TypeScript перестает проверять элементы
Третья ошибка — типизировать массив как один объект:
const users: User = [];
Правильно:
const users: User[] = [];
Четвертая ошибка — забывать optional-поля и обращаться к ним как к обязательным
Пятая ошибка — верить, что TypeScript проверил API-ответ в runtime
Вложенные объекты
Если у элемента массива есть вложенная структура, ее тоже лучше вынести в тип:
type Address = {
city: string;
street: string;
};
type Customer = {
id: number;
name: string;
address: Address;
};
const customers: Customer[] = [
{
id: 1,
name: "Dinar",
address: {
city: "Kazan",
street: "Main",
},
},
];
Так типы остаются читаемыми. Если вложенный объект описывать прямо внутри Customer, материал быстро становится тяжелым, особенно когда такая структура используется в нескольких местах
Самопроверка
Создайте тип Order с полями id, total, status. Сделайте const orders: Order[]. Затем специально добавьте объект без total и объект со status: 123. TypeScript должен подсветить обе ошибки
Что почитать дальше по TypeScript
Если нужен общий маршрут по теме, откройте рубрику TypeScript. Для соседних задач пригодятся эти разборы:
- TypeScript массив объектов: как описать и проверить элементы
- TypeScript Map: как типизировать ключи и значения
- TypeScript функция как аргумент: как типизировать callback
- Как типизировать объект в TypeScript: практический разбор



