TypeScript
Основы
Каждое значение в JavaScript
при выполнении над ним каких-либо операций ведет себя определенным образом. Это может звучать несколько абстрактно, но, в качестве примера, попробуем выполнить некоторые операции над переменной message
:
// Получаем доступ к свойству `toLowerCase`
// и вызываем его
message.toLowerCase()
// Вызываем `message`
message()
На первой строке мы получаем доступ к свойству toLowerCase
и вызываем его. На второй строке мы пытаемся вызвать message
.
Предположим, что мы не знаем, какое значение имеет message
- обычное дело - поэтому мы не можем с уверенностью сказать, какой результат получим в результате выполнения этого кода.
- Является ли переменная
message
вызываемой? - Имеет ли она свойство
toLowerCase
? - Если имеет, является ли
toLowerCase
вызываемым? - Если оба этих значения являются вызываемыми, то что они возвращают?
Ответы на эти вопросы, как правило, хранятся в нашей памяти, поэтому остается только надеяться, что мы все помним правильно.
Допустим, message
была определена следующим образом:
const message = 'Hello World'
Как вы, наверное, догадались, при запуске message.toLowerCase()
мы получим ту же строку, только в нижнем регистре.
Что насчет второй строки кода? Если вы знакомы с JS
, то знаете, что в этом случае будет выброшено исключение:
TypeError: message is not a function
// Ошибка типа: message - это не функция
Было бы здорово, если бы мы имели возможность избегать подобных ошибок.
При запуске нашего кода, способ, с помощью которого движок JS
определяет, что делать, заключается в выяснении типа (type) значения - каким поведением и возможностями он обладает. На это намекает TypeError
- она говорит, что строка 'Hello World'
не может вызываться как функция.
Для некоторых значений, таких как примитивы string
и number
, мы можем определить их тип во время выполнения кода (runtime) с помощью оператора typeof
. Но для других значений, таких как функции, соотв етствующий механизм для определения типов во время выполнения отсутствует. Например, рассмотрим следующую функцию:
function fn(x) {
return x.flip()
}
Читая этот код, мы можем сделать вывод, что функция будет работать только в случае передачи ей объекта с вызываемым свойством flip
, но JS
не обладает этой информацией. Единственным способом определить, что делает fn
с определенным значением, в чистом JS
является вызов этой функции. Такой вид поведения затрудняет предсказание поведения кода во время его написания.
В данном случае тип - это описание того, какие значения могут передаваться в fn
, а какие приведут к возникновению ошибки. JS
- это язык с динамической (слабой) типизацией - мы не знаем, что произойдет, до выполнения кода.
Статическая система типов позволяет определять, что ожидает код до момента его выполнения.