Array<Type> vs Type[] в TypeScript: битва синтаксисов, которую вы обязаны выиграть
Если вы когда-нибудь писали на TypeScript, вы точно видели два способа объявить массив чисел:
const numbers1: number[] = [1, 2, 3];
const numbers2: Array<number> = [1, 2, 3];
Оба варианта работают. Оба компилируются. Оба — валидный TypeScript. Так зачем же вокруг них столько споров? Почему этот вопрос на Stack Overflow собрал тысячи просмотров? И главное — как не наступить на грабли, которые сломают ваш проект?
Давайте разберёмся раз и навсегда. Без скучной теории. Только то, что реально пригодится в бою.
Краткий ликбез: что есть что
Синтаксис Type[] (Array Literal Syntax)
Это самый распространённый способ объявить массив в TypeScript. Он пришёл из JavaScript и выглядит естественно:
let fruits: string[] = ['apple', 'banana', 'cherry'];
let matrix: number[][] = [[1, 2], [3, 4]]; // Массив массивов
Коротко, читаемо, интуитивно. Для 90% случаев этого достаточно.
Синтаксис Array<Type> (Generic Syntax)
Это дженерик-форма, использующая встроенный интерфейс Array<T>:
let fruits: Array<string> = ['apple', 'banana', 'cherry'];
let matrix: Array<Array<number>> = [[1, 2], [3, 4]];
Выглядит более "академично", но даёт больше гибкости в сложных сценариях.
Топ-5 ошибок, которые допускают даже опытные разработчики
Ошибка №1: Слепое доверие к автокомплиту IDE
Ваша IDE может подсказывать оба варианта. Но это не значит, что они взаимозаменяемы везде. Рассмотрим пример с union-типами:
// Так можно
type Status = 'active' | 'inactive';
const statuses1: Status[] = ['active', 'inactive'];
// А так — синтаксическая ошибка!
// const statuses2: Array<'active' | 'inactive'> = ['active', 'inactive'];
// ❌ Ошибка: ';' expected
// Правильный вариант с дженериком:
const statuses3: Array<Status> = ['active', 'inactive'];
Вывод: Внутри Array<> нельзя использовать сложные union-типы напрямую. Сначала вынесите их в отдельный тип.
Ошибка №2: Путаница с readonly массивами
Когда нужно сделать массив неизменяемым, синтаксисы ведут себя по-разному:
// ✅ Правильно с Type[]
const readonlyFruits: readonly string[] = ['apple', 'banana'];
// readonlyFruits.push('orange'); // ❌ Ошибка: readonly
// ❌ Так не сработает:
// const wrong: readonly Array<string> = ['apple'];
// Ошибка: 'readonly' modifier can only appear on array types
// ✅ Правильно с Array<> — используйте ReadonlyArray:
const correct: ReadonlyArray<string> = ['apple', 'banana'];
Вывод: Для readonly массивов используйте readonly Type[] или ReadonlyArray<Type>. Смешивать readonly с Array<> нельзя.
Ошибка №3: Проблемы с многоуровневыми массивами
Когда массив содержит другие массивы, синтаксис Array<> становится громоздким:
// Читаемо и понятно
const grid1: number[][] = [[1, 2], [3, 4]];
// Уже сложнее читать
const grid2: Array<Array<number>> = [[1, 2], [3, 4]];
// А если три уровня? Кошмар:
const cube: Array<Array<Array<number>>> = [[[1]]]; // 🤯
// С Type[] всё проще:
const cube2: number[][][] = [[[1]]];
Вывод: Для массивов с вложенностью больше 2 используйте Type[][]. Ваши коллеги скажут спасибо.
Ошибка №4: Игнорирование контекста использования
В некоторых фреймворках (Angular, React) и библиотеках принят определённый стиль. Нарушение конвенции может вызвать путаницу:
// Angular часто использует Array<Type> в сервисах
@Injectable()
export class UserService {
users: Array<User> = []; // Стиль Angular
}
// React-разработчики предпочитают Type[]
function UserList() {
const [users, setUsers] = useState<User[]>([]); // Стиль React
}
Вывод: При работе в команде соблюдайте code-style. Если проект использует Array<Type> — не пишите Type[] и наоборот.
Ошибка №5: Забываем про дженерики в функциях
Когда вы пишете функцию, которая принимает массив любого типа, дженерик-синтаксис — единственный правильный выбор:
// ❌ Так нельзя — Type не определён
// function firstElement(arr: Type[]): Type {
// return arr[0];
// }
// ✅ Правильно с Array<T>
function firstElement<T>(arr: T[]): T {
return arr[0];
}
// Тоже правильно, но менее читаемо:
function firstElement2<T>(arr: Array<T>): T {
return arr[0];
}
Вывод: В объявлениях дженерик-функций оба синтаксиса равноправны. Выбирайте тот, который принят в вашем проекте.
Когда что использовать? Чёткие правила
Чтобы больше никогда не ломать голову, запомните эту таблицу:
| Ситуация | Рекомендуемый синтаксис | Пример |
|---|---|---|
| Простой массив (1 уровень) | Type[] |
string[] |
| Многомерный массив | Type[][] |
number[][] |
| Readonly массив | readonly Type[] |
readonly number[] |
| Сложный union внутри | Array<Type> |
Array<Status
|