Как правильно объявить массив объектов в TypeScript: полное руководство для новичков
Основные способы объявления массива объектов в TypeScript
В TypeScript существует несколько способов объявить массив объектов. Каждый подход имеет свои преимущества и используется в зависимости от ситуации. Рассмотрим все варианты от простых к более сложным.
1. Inline-типизация (для простых случаев)
Самый быстрый способ — объявить тип прямо в параметре или переменной:
const users: { name: string; age: number }[] = [
{ name: "Иван", age: 25 },
{ name: "Мария", age: 30 }
];
function getUserNames(users: { name: string; age: number }[]) {
return users.map(user => user.name);
}
Плюсы: быстро, не нужно создавать отдельный тип.
Минусы: если массив используется в нескольких местах, придётся дублировать тип.
2. Использование type alias (рекомендуется)
Лучшая практика — вынести тип объекта в отдельный алиас:
type User = {
name: string;
age: number;
};
const users: User[] = [
{ name: "Иван", age: 25 },
{ name: "Мария", age: 30 }
];
function getUserNames(users: User[]) {
return users.map(user => user.name);
}
Такой подход даёт полное автодополнение в редакторе и возможность переиспользовать тип User в других функциях.
3. Использование interface (альтернатива type)
interface IUser {
name: string;
age: number;
}
const users: IUser[] = [
{ name: "Иван", age: 25 },
{ name: "Мария", age: 30 }
];
Разница между type и interface минимальна для простых объектов. interface лучше расширяется, type — более гибкий.
4. Массив с необязательными полями
Если некоторые поля могут отсутствовать, используйте оператор ?:
type User = {
name: string;
age: number;
phone?: string; // необязательное поле
};
const users: User[] = [
{ name: "Иван", age: 25, phone: "+7-999-123-45-67" },
{ name: "Мария", age: 30 } // phone отсутствует — это нормально
];
5. Generic Array<T> синтаксис
Можно использовать дженерики вместо квадратных скобок:
const users: Array<User> = [
{ name: "Иван", age: 25 },
{ name: "Мария", age: 30 }
];
Этот синтаксис полностью эквивалентен User[]. Выбор — дело вкуса.
6. Массив с разными типами объектов (union)
Если в массиве могут быть объекты разных форм, используйте объединение типов:
type Admin = {
name: string;
role: "admin";
permissions: string[];
};
type RegularUser = {
name: string;
role: "user";
age: number;
};
type Person = Admin | RegularUser;
const people: Person[] = [
{ name: "Иван", role: "admin", permissions: ["read", "write"] },
{ name: "Мария", role: "user", age: 30 }
];
7. ReadonlyArray — если массив не должен изменяться
const users: ReadonlyArray<User> = [
{ name: "Иван", age: 25 }
];
// users.push({ name: "Пётр", age: 28 }); // Ошибка! Нельзя изменять
Что выбрать новичку?
- Для простых скриптов — inline-типизация
- Для реальных проектов — type alias + User[]
- Если планируете расширять тип — interface
- Для необязательных полей — оператор ?
- Для гетерогенных массивов — union types
Главное правило: всегда явно указывайте тип массива объектов. Это даёт автодополнение, защиту от ошибок и самодокументируемый код.
<<Альтернативный подход: утилитарные типы и Record
Иногда удобнее использовать встроенные утилиты TypeScript для создания массива объектов, особенно когда структура динамическая или повторяющаяся.
1. Record для однотипных объектов
type User = Record<'name' | 'age' | 'phone', string | number>;
const users: User[] = [
{ name: "Иван", age: 25, phone: "+7-999-123-45-67" },
{ name: "Мария", age: 30, phone: "+7-999-987-65-43" }
];
Недостаток: все поля становятся одного типа (string | number), теряется точность.
2. Tuple для фиксированной структуры
Если массив всегда содержит строго определённое количество объектов:
type Pair = [User, User]; // ровно два объекта
const pair: Pair = [
{ name: "Иван", age: 25 },
{ name: "Мария", age: 30 }
];
3. as const для литеральных типов
Если массив объектов не будет изменяться и вы хотите максимально точные типы:
const users = [
{ name: "Иван", age: 25 },
{ name: "Мария", age: 30 }
] as const;
// users[0].name — тип "Иван", а не string
4. Когда использовать эти подходы
- Record — для быстрой типизации, когда точность не критична
- Tuple — для пар или троек объектов с разным смыслом
- as const — для конфигураций, enum-подобных массивов
Однако для 90% случаев лучше всего подходит классический подход с type или interface, описанный в первом ответе. Эти альтернативы — для специфических сценариев.