Как и в JavaScript, в TypeScript есть специальные типы undefined и null, которые принимают соответствующие значения undefined и null.
Использование undefined
и null
зависит от параметра компиляции strictNullChecks.
По умолчанию он имеет значение false
и не используется, а это значит, что по умолчанию мы можем применять эти типы, как и в javascript:
let a: undefined = undefined; let b: null = null;
Но фактически мы можем присваивать значения undefined и null переменным других типов, например, number:
let x: number = undefined; console.log(x); x = null; console.log(x); x = 5; console.log(x);
В этом плане null и undefined выступают как подтипы других типов и полезны преимущественно в каких-то операциях, где неизвестен результат - то ли это будет число или строка, то ли это будет null. В этом случае, чтобы избежать возможной ошибки, мы можем проверить значение на undefined или null, собственно как и в javascript.
В то же время отсутствие проверки для этих типов со стороны компилятора является потенциальным источников багов, поэтому нередко при компиляции применяется параметр strictNullChecks. Либо при установке флага при компиляции в консоли:
--strictNullChecks
Либо с помощью установки значения true
в файле конфигурации tsconfig.json:
{ "compilerOptions": { "target": "es2015", "noImplicitAny": true, "noEmitOnError": true, "strictNullChecks": true, "outFile": "app.js" } }
В этом случае при попытке присвоить значение типа undefined
или null
переменной другого типа компилятор при компиляции
выбросит ошибку. Например, при компиляции предыдущего примера кода:
let x: number = undefined; console.log(x); x = null; console.log(x); x = 5; console.log(x);
Мы получим следующие ошибки:
Также мы получим ошибку, если значение undefined
присвоим переменной типа null
или значение null
переменной типа undefined
.
Тем не менее нередки ситуации, когда мы точно не знаем, имеет ли какая-то переменная или параметр функции или конкретное значение или оно отсутствует.
Особенно в тех случааях, когда мы получаем значение из вне, например, с помощью запроса к какому-нибудь сетевому ресурсу. В этом случае может потребоваться,
чтобы переменная или параметр могли принимать значение null
. И в этом случае можно использовать объединения. Например:
let userId: number|null = null; function printId(id: number|null){ if (id === null) { console.log("пользователь отсутствует"); } else { console.log(`id пользователя: ${id}`); } } printId(userId) // пользователь отсутствует userId = 45; printId(userId); // id пользователя: 45
В данном случае переменная userId
представляет объединение number|null
, поэтому этой переменной можно присвоить как конкретное числовое
значение, так и значение null
.
Аналогично функция printId
через параметр id
может принимать как значение null
, так и числовое значение.
Оператор ! (non-null assertion operator) позволяет указать, что объект не представляет значение null
и undefined
. Так,
возьмем следующий пример:
const header: HTMLElement|null = document.getElementById("header"); header.innerText = "Hello Typescript!";
Встроенная функция document.getElementById()
возвращает элемент веб-страницы по id, который представляет тип HTMLElement|null.
То есть он может иметь значение null
, если html-элемента с подобным id нет на веб-странице.
Получив элемент, мы пытаемся с помощью его свойства innerText
изменить его текстовое содержимое.
Вроде все нормально, однако умолчанию с включенной опцией strictNullChecks
при компиляции мы получим ошибку:
Чтобы избежать ошибки, используем оператор !:
const header: HTMLElement|null = document.getElementById("header"); header!.innerText = "Hello Typescript!";
Оператор ! ставится после объекта, который теоретически может принимать значение null
перед обращением к его свойствам и методам:
object!.property object!.method()
В то же время надо учитывать, что этот оператор не меняет значения объекта. Например, если объект имеет значение null или undefined, то данный оператор не поможет. Программа скомпилируется, но при выполнении скрипта программа все равно сгенерирует ошибку:
const header: HTMLElement|null = null; header!.innerText = "Hello Typescript!";
Поэтому рекомендуется применять данный оператор, когда мы знаем, что объект не равен null или undefined.