Array<Type> vs Type[] в TypeScript: 5 фатальных ошибок и как их избежать

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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

Блоги

Рекомендаций по книгам