TypeScript Null и Undefined
В TypeScript есть мощная система для работы со значениями, которые могут быть null или undefined.
Примечание: По умолчанию эта проверка отключена. Включите её, установив strictNullChecks в значение true в параметрах компилятора. Дальше на этой странице предполагается, что strictNullChecks включён.
Типы
null и undefined — примитивные типы. Их можно использовать в аннотациях типов так же, как string или number, например внутри объединения.
Примечание: При включённом strictNullChecks TypeScript ожидает, что каждое значение задано, если только undefined явно не входит в его тип.
Пример
Переменная принимает строку, undefined или null, поэтому разрешены все три присваивания.
null и undefined в качестве членов объединения типов.
Объявите value с типом string | undefined | null, инициализируйте его значением null, затем присвойте ему 'hello', а после — undefined. Файл только присваивает значения и ничего не выводит.
Вывод: программа на TypeScript и захваченный вывод
let value: string | undefined | null = null;
value = 'hello';
value = undefined;
Опциональная цепочка
Опциональная цепочка — возможность JavaScript, которая хорошо сочетается с обработкой null в TypeScript.
Она позволяет прочитать свойство объекта, который может существовать, а может и нет, очень коротким синтаксисом.
Используйте оператор ?. при обращении к свойству. Если объект перед ?. равен null или undefined, всё выражение становится undefined вместо выброса ошибки.
Пример
house.yard?.sqft равно undefined, когда у дома нет двора, поэтому функция выводит Двора нет.
?. на необязательном вложенном свойстве.
Объявите интерфейс House со свойством sqft: number и необязательным объектом yard, у которого есть своё sqft: number. Напишите printYardSize(house: House), который считывает house.yard?.sqft, выводит 'Двора нет', когда результат равен undefined, и иначе выводит Двор: <размер> кв. футов. Создайте home со sqft 500 и без двора и вызовите функцию, чтобы она вывела 'Двора нет'.
Вывод: программа на TypeScript и захваченный вывод
interface House {
sqft: number;
yard?: {
sqft: number;
};
}
function printYardSize(house: House) {
const yardSize = house.yard?.sqft;
if (yardSize === undefined) {
console.log('Двора нет');
} else {
console.log(`Двор: ${yardSize} кв. футов`);
}
}
let home: House = {
sqft: 500
};
printYardSize(home); // Выводит 'Двора нет'
Нулевое слияние
Нулевое слияние — ещё одна возможность JavaScript, которая хорошо работает с обработкой null в TypeScript.
Она позволяет задать выражению запасное значение, которое используется только тогда, когда значение равно null или undefined.
Это полезно, когда могут встречаться другие ложные значения, такие как 0 или пустая строка, и они при этом остаются допустимыми.
Используйте в выражении оператор ?? похожим образом на оператор &&.
Пример
mileage ?? 'Нет данных' подставляет запасное значение для null, но сохраняет 0, потому что 0 не является нулевым значением.
?? как запасное значение только для null и undefined.
Напишите printMileage(mileage: number | null | undefined), который выводит Пробег: , а затем mileage ?? 'Нет данных'. Вызовите его с null (выводит 'Пробег: Нет данных') и с 0 (выводит 'Пробег: 0').
Вывод: программа на TypeScript и захваченный вывод
function printMileage(mileage: number | null | undefined) {
console.log(`Пробег: ${mileage ?? 'Нет данных'}`);
}
printMileage(null); // Выводит 'Пробег: Нет данных'
printMileage(0); // Выводит 'Пробег: 0'
Ненулевое утверждение
Вывод типов в TypeScript не идеален. Иногда вы знаете, что значение не может быть null или undefined, хотя его тип говорит, что может.
Можно было бы использовать приведение типа, но TypeScript также даёт оператор ! как короткий способ сказать «это значение точно задано».
Примечание: Как и приведение типа, это может быть небезопасно. Используйте с осторожностью.
Пример
getValue() возвращает string | undefined. Запись value!.length говорит TypeScript считать value строкой.
!.
Напишите getValue() с типом возврата string | undefined, который возвращает 'hello', сохраните результат в value и выведите 'длина value: ' плюс value!.length, чтобы в выводе была длина 5.
Вывод: программа на TypeScript и захваченный вывод
function getValue(): string | undefined {
return 'hello';
}
let value = getValue();
console.log('длина value: ' + value!.length);
Обработка границ массива
Даже при включённом strictNullChecks TypeScript по умолчанию считает, что чтение элемента массива никогда не даёт undefined (если только undefined не входит в тип элементов массива).
Параметр компилятора noUncheckedIndexedAccess меняет это. При его включении к типу каждого чтения по индексу добавляется undefined.
Пример
По умолчанию array[0] имеет тип number. С noUncheckedIndexedAccess он становится number | undefined.
noUncheckedIndexedAccess.
Объявите array с типом number[], содержащий 1, 2 и 3, затем считайте array[0] в value с комментарием о том, что при noUncheckedIndexedAccess тип был бы number | undefined. Ничего не выводится.
Вывод: программа на TypeScript и захваченный вывод
let array: number[] = [1, 2, 3];
let value = array[0]; // при включённом `noUncheckedIndexedAccess` тип будет `number | undefined`