Как типизировать массив объектов в TypeScript

Короткий ответ: сначала опишите тип одного объекта, а затем укажите массив этого типа: 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. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x