ПрограммированиеFullstack разработчик

Как работает типизация массивов в TypeScript, как правильно объявлять массивы с элементами разного типа, и какие есть способы описывать их с помощью кортежей (tuples)? Приведите примеры и объясните возможные ошибки, связанные с работой с такими структурами.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В TypeScript массивы описываются двумя основными способами: тип[] и Array<тип>. Для массивов с элементами разного типа используются объединенные типы (union types) или кортежи (tuples), которые позволяют описывать фиксированный набор элементов разного типа и количества.

Объявления массивов:

let numbers: number[] = [1, 2, 3]; let strings: Array<string> = ['a', 'b', 'c'];

Массив с элементами разных типов:

let mixed: (string | number)[] = [1, 'a', 2];

Кортежи (tuples):

let tuple: [string, number, boolean] = ['hello', 42, true];

С кортежами удобнее работать, когда ожидается фиксированная структура (например, вернуть из функции сразу несколько разных по типу значений), а с массивами — когда количество и тип элементов может быть перемешано или неизвестно заранее.

Вопрос с подвохом.

Можно ли после определения кортежа с длиной N добавить к нему элементы с помощью push? Как это влияет на типизацию?

Ответ: Да, пушить в кортеж можно — компилятор разрешает это, хотя это нарушает предпосылку ограниченности корретжа по длине. Типы новых элементов будут приводиться к объединению всех возможных типов элементов кортежа:

let tuple: [number, string] = [42, 'foo']; tuple.push(true); // OK! tuple now: [number, string, boolean], но тип не обновился, а ошибки нет! console.log(tuple); // [42, 'foo', true]

Поэтому работу с кортежами и их изменяемость нужно контролировать вручную или делать их readonly.

Примеры реальных ошибок из-за незнания тонкостей темы.


История

Разработчик описал функцию, возвращающую кортеж [number, string], но затем начал добавлять к результату элементы через push. Это привело к рассинхронизации типов: последующий код ожидал ровно два элемента с определёнными типами, но получал массив переменной длины, из-за чего возникали рантайм-ошибки при распаковке значений и чтении по несуществующим индексам.


История

Для хранения массива значений разных типов был использован массив any[], считая это универсальным решением. В результате TypeScript перестал проверять правильность типов, и логика приложения начала "ломаться" из-за неправильных преобразований типов, которые не вызывали ошибок компиляции.


История

В проекте массив описывался либо через тип[], либо через Array<тип> — но в одних местах допускалась запись let arr: any[] (чтобы работать "с чем угодно"). Из-за этого появлялись неконтролируемые преобразования, функцию принимала любой массив, что приводило к runtime-ошибкам при попытке вызвать некорректные методы для элементов разных типов.