TypeScript со строгой проверкой нуля - как насчет доступа к массиву?
В TypeScript, если включена строгая проверка нуля, я ожидаю, что компилятор не позволит мне назначить null
или же undefined
значения переменной, если она не допускает null
,
Однако доступ к массиву позволяет обойти эту проверку.
Пример:
let a: string[] = ["Hello"];
let s: string;
// 1) this produces an error, as expected
s = undefined
// 2) s is undefined here, too, but no error
s = a[3];
console.log(s);
Запускаемая версия на TypeScript Playground (примечание: в диалоговом окне "Параметры" должна быть включена "строгая проверка нуля").
Что здесь происходит?
- Это ошибка в компиляторе TypeScript?
- Или это намеренное упущение?
- Если последнее, документировано ли это где-нибудь (в идеале с обоснованием, почему это было сделано)?
2 ответа
Нашел это:-).
tl; dr: это намеренное упущение. Доступ к массиву очень распространен в коде TypeScript, и принудительная проверка нулевого / неопределенного для каждого доступа считалась слишком громоздкой для разработчиков.
Эта проблема поднималась несколько раз в дискуссиях:
- проблема № 11122 - поиск в массиве должен возвращать T | не определено
- прокомментировать PR 7140
- # 6229 - Предложение: строгие и открытые типы кортежей
Комментарий к PR 7140 имеет хорошее обоснование от Андерса Хейлсберга (одного из разработчиков ядра):
Индексирование просто создает значение типа, объявленного в соответствующей сигнатуре индекса. Даже если это технически более правильно, было бы слишком больно, если бы мы автоматически добавили
undefined
к типу каждой операции индексации.Например, каждый доступ к элементу массива должен сопровождаться ненулевой защитой или
!
утверждение. Я думаю, это стало бы очень раздражающим.
TypeScript 4.1 представил новую опцию компилятора — noUncheckedIndexedAccess. Среди прочего добавляется
undefined
к типу доступа к индексу массива.
Рассмотрим следующий фрагмент (игровая площадка TS ):
const items = [1,2,3]
console.log(items[1]?.toString(10))
console.log(items[2].toString(10))
Без
noUncheckedIndexedAccess
,
items[2].toString(10)
будет считаться действительным и недействительным, если опция включена.
items[1]?.toString(10)
будет действителен, когда эта опция включена, как в комментарии Алекса Нета в старом ответе.