Операторы - Optional, Not-Null Not-Undefined, Definite Assignment Assertion¶
Оператор Optional
, помечающий члены и параметры как необязательные, довольно часто используется при разработке приложений. И, если в понимании механизма его работы нет ничего сложного, то для идеологически связанного с ним оператора Not-Null Not-Undefined
не все так очевидно.
Необязательные поля, параметры и методы (Optional Fields, Parameters and Methods)¶
В TypeScript существует возможность декларировать поля, методы и параметры как необязательные. Эта возможность позволяет исключать помеченные элементы из инициализации, вызовов и проверки на совместимость.
Поле, параметр или метод, как необязательный помечается с помощью оператора вопросительного знака ?
. При объявлении полей и параметров, оператор помещается сразу после идентификатора identifier?: Type
. Для методов оператор помещается между идентификатором и круглыми скобками identifier?(): Type
.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Термины поля, параметры, методы делают данный оператор чересчур именитым. Поэтому в дальнейшем он будет упрощен до “необязательного оператора”.
Из темы, посвященной типу undefined
, стало известно, что он является подтипом всех типов. Это, в свою очередь, означает, что его единственное значение undefined
можно присвоить в качестве значения любому другому типу.
1 2 3 4 5 6 7 |
|
Когда у компилятора флаг --strictNullChecks
установлен в true
, тип undefined
является подтипом только типа any
. Это означает, что связать значение undefined
можно только с типом any
.
1 2 3 4 5 6 7 |
|
Как было сказано в начале, необязательное буквально означает, что параметр функции может быть не ассоциирован со значением, а поле или метод и вовсе не существовать в объекте. А, как известно, неинициализированные члены объектов и параметры функции всегда принадлежат к типу undefined
. Поэтому каждый раз, когда компилятор видит поля или параметры, помеченные как необязательные, он расценивает это как явное указание на сценарий, допускающий значение undefined
, способное нарушить ожидаемый ход выполнения программы. И, поскольку активация рекомендуемого флага --strictNullChecks
запрещает присваивать значение undefined
типам, отличным от undefined
или any
, вывод типов берет на себя инициативу и помечает все необязательные конструкции как принадлежащие к объединению, включающему тип undefined
.
1 2 3 4 5 6 7 8 |
|
Когда флаг --strictNullChecks
установлен в false
и он встречает поля или параметры, помеченные как необязательные, он точно также понимает, что по сценарию допускается значение undefined
. Но при этом он не добавляет к уже указанному типу тип undefined
и даже не берет его в расчет при явном указании. Такое поведение связано с тем, что при неактивном флаге --strictNullChecks
тип данных undefined
совместим со всеми остальными типами. Это в свою очередь освобождает поля и параметры от его явного указания.
1 2 3 4 5 6 7 8 |
|
Также стоит упомянуть, что необязательные поля не обязательно должны содержать явную аннотацию.
1 2 3 4 5 6 7 8 |
|
Оператор ! (Non-Null and Non-Undefined Operator)¶
Оператор Not-Null Not-Undefined
при активной опции --strictNullChecks
в случаях, допускающих обращение к несуществующим членам, позволяет приглушать сообщения об ошибках.
Простыми словами, когда в режиме --strictNullChecks
происходит обращение к значению объекта или метода, которые могут иметь значение null
или undefined
, компилятор с целью предотвращения возможной ошибки накладывает запрет на операции обращения и вызова. Разрешить подобные операции возможно с помощью оператора Not-Null Not-Undefined
, который обозначается восклицательным знаком !
.
Чтобы понять принцип оператора Non-Null Non-Undefined
достаточно представить слушатель события, у которого единственный параметр event
, принадлежность которого указана к типу UserEvent
, помечен как необязательный. Это означает, что помимо обусловленного типа UserEvent
, параметр может принадлежать ещё и к типу undefined
. А это значит, что при попытке обратиться к какому-либо члену объекта события event
, может возникнуть исключение, вызванное обращением через ссылку на null
или undefined
. С целью предотвращения исключения во время выполнения, компилятор, во время компиляции, выведет сообщение об ошибке, вызванной обнаружением потенциально опасного кода.
1 2 3 4 5 6 7 8 9 10 |
|
Обычно в таких случаях стоит изменить архитектуру, но если разработчик в полной мере осознает последствия, то компилятор можно настоятельно попросить закрыть глаза на потенциально опасное место при помощи оператора Not-Null Not-Undefined
. При обращении к полям и свойствам объекта, оператор Not-Null Not-Undefined
указывается перед оператором точка object!.field
.
1 2 3 4 5 6 7 8 9 |
|
Оператор Not-Null Not-Undefined
нужно повторять каждый раз, когда происходит обращение к полям и свойствам объекта, помеченного как необязательный.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
При обращении к необязательным методам объекта, оператор Not-Null Not-Undefined
указывается между идентификатором (именем) и круглыми скобками. Стоит обратить внимание, что когда происходит обращение к необязательному полю или свойству объекта, оператор Not-Null Not-Undefined
указывается лишь один раз optioanlObject!.firstLevel.secondLevel
. При обращении к необязательному методу того же объекта, оператор Not-Null Not-Undefined
указывается дважды optionalObject!.toString!()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Нужно повторить ещё раз, что оператор Not-Null Not-Undefined
при активном флаге --strictNullChecks
обязателен только в случаях, когда объект принадлежит к типу, отличному от any
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
И, как было сказано в самом начале, правило оператора Not-Null Not-Undefined
, применённое к необязательному оператору, идентично для всех полей и параметров, принадлежащих к типам null
или undefined
...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
...при условии, что они не будут принадлежать к типу any
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Оператор ! (Definite Assignment Assertion)¶
Для повышения типобезопасности программы, правила, накладываемые опцией --strictNullChecks
(глава Опции компилятора), действуют также на переменные, инициализирующиеся в чужом контексте.
1 2 3 4 5 6 7 8 9 10 |
|
Чтобы избежать ошибки при обращении к переменным, которые инициализированы в чужом контексте, нужно использовать definite assignment assertions. Definite assignment assertions также указывается с помощью символа восклицательного знака (!
) и располагается после идентификатора переменной. Указывая данный оператор каждый раз при обращении к переменной, разработчик сообщает компилятору, что берет на себя все проблемы, которые могут быть вызваны отсутствием значения у переменной.
1 2 3 4 5 6 7 8 9 10 |
|