Функции
Тип функции
Функция в TypeScript объявляется почти также, как и в JavaScript. Главное отличие - нужно обязательно типизировать параметры. Они типизируются при помощи :
, по аналогии с предыдущими конструкциями.
Параметры функции могут быть любыми типами. При вызове функции TypeScript будет проверять совместимость типа значения, переданного в качестве параметра, с типом этого параметра. Если типы будут не совместимы - будет ошибка компиляции
Необязательные параметры и параметры со значением
Если при вызове функции будет передано меньшее или большее количество параметров, чем было указано при объявлении - TypeScript выдаст ошибку.
Иногда возникает необходимость объявить функцию, у которой есть необязательные параметры. Для этого (как и для необязательных полей объекта) необходимо использовать символ ?
.
В случае, когда параметр отмечен, как не обязательный, TypeScript объединяет тип параметра с типом undefined
. Это объясняется тем, что в runtime, если необязательный параметр не был передан, то в функции его значение будет undefined
. Однако иногда требуется задать какому-то параметру значение по умолчанию.
Если параметру задается значение по умолчанию, то TypeScript может применить автовывод типа параметра по значению (по обычным правилам автовывода типа).
Все необязательные параметры должны объявляться в конце списка параметров. Пред заполненные параметры могут находится в любом месте списка параметров.
rest
параметр
rest
параметрЧтобы передать в функцию неограниченное количество параметров, в JavaScript используется rest
параметр. Для того, чтобы объявить rest
параметр в TypeScript нужно указать его тип в виде массива. Если нужно передать в функцию неограниченное количество массивов, то нужно указать тип массив массивов.
rest
параметр должен быть самым последним параметром (даже после опциональных). Соответственно, у функции не может быть два и более rest
параметров, так как хотя бы один из них будет не последним.
Типизация this
this
В JavaScript реализована особая работа с контекстом выполнения функции. Поэтому при работе с TypeScript может потребоваться определить тип для this
. Для этого необходимо в списке параметров самым первым определить параметр с названием this
и указать тип для него. Этот параметр нужен только для того, чтобы TypeScript понял тип контекста выполнения функции. При вызове функции его передавать не нужно.
Если при определении функции был указан тип для this
, то вызов методов apply
и call
могут принимать значение контекста, которое совместимо с типом, указанном при объявлении.
Типизация возвращаемого значения
Тип возвращаемого значения функции указывается сразу после списка параметров при помощи :
Если тип значения, которое возвращает функция, не совместим с типом возвращаемого значения - TypeScript возвращает ошибку.
Для того, чтобы указать, что функция ничего не возвращает, используется тип void
(не never
).
Если явно не указать тип возвращаемого значения функции, то TypeScript выведет его автоматически в зависимости от тела функции.
Вынесение типа функции
Как и любой другой тип в TypeScript, тип функции можно вынести в type
. Также можно явно типизировать типом функции переменную, поле объекта, даже параметр или возвращаемое значение другой функции. Синтаксис типа функции выглядит так:
Для описания типа важно знать только список параметров функции, их типы и тип возвращаемого значения. Тип возвращаемого значения указывается при помощи =>
(важно - :
не используется). Проверки соответствия функции с требуемым типом осуществляется по типам параметров (включая опциональные параметры, rest
параметры и типизацию this
) и по типу возвращаемого значения.
Если у переменной, параметра, поля или возвращаемого значения явно задан тип функции, то при написании значения указывать типы параметров необязательно.
Функция может содержать не все параметры, которые указаны в типе функции:
Это возможно потому, что несмотря на то, что реализация функции использует не все (а может и никакие) параметры, указанные в типе функции, вызвать функцию все равно можно только со всеми параметрами.
Такая особенность позволяет не использовать все требуемые параметры, когда они не нужны. Это часто используется при описании callback-ов.
Перегрузка
В JavaScript можно объявить функцию, которая может возвращать значения разных типов. Более того, один и тот же параметр может принимать значения разных типов. Например, опишем функцию lalaka
, которая принимает 2 параметра: параметр a: "string" | "number"
, который указывает тип для значения второго параметра, и второй параметр b: string | number
в который передается значение того типа, который указан в первом параметра. Если первый параметр "string"
, то второй параметр должен быть строкой, а возвращаемое значение - объект вида {a: b}
. А если первый параметр "number"
, то второй параметр - число и в результате функция должна вернуть результат операции b + 10
. Для описания такой функции в TypeScript можно попробовать воспользоваться объединением типов или типом any
.
В данном случаи TypeScript не может гарантировать, что если в пером параметра передано значение "number"
, то второй параметр будет number
, то есть оба параметра считаются независимыми. Поэтому в объявлении функции ошибка. Более того, возвращаемое значение функции any
, из-за чего с результатом функции можно делать что угодно (например, сравнивать значение несуществующего поля).
Для того, чтобы улучшить типизацию этой функции можно воспользоваться перегрузкой. Перегрузка - это возможность указать несколько типов (несколько сигнатур) для одной и той же функции. Компилятор TypeScript будет сопоставлять типы переданных параметров с перегрузками функции и, если у функции не будет подходящего типа, выдаст ошибку.
Для того, чтобы объявить перегрузки для функции, нужно сначала указать сигнатуры перегрузок функции, а затем написать функцию реализацию.
В данном случаи первая и вторая сигнатура функции - это доступные для использования перегрузки (объявляются без тела функции), а последняя - это функция реализация. В функции-реализации описывается то, что на самом деле будет выполняться в runtime. Как было сказано выше, компилятор будет выбирать перегрузку подходящую под переданные параметры. Соответственно, если в функцию foo
будет передано значение типа number
, то компилятор выберет первую перегрузку с возвращаемым значением типа number
Сигнатура функции-реализации должна учитывать все сигнатуры перегрузок. То есть типы всех параметров и тип возвращаемого значения функции-реализации должны быть совместимы с соответствующими типами всех перегрузок. Если функция-реализация не будет соответствовать хотя бы одной перегрузке - будет ошибка.
С использованием перегрузок функции пример функции lalaka
будет выглядеть так:
Функция как объект
Ранее было сказано, что при помощи type
и interface
можно описать тип объекта. Но функция тоже является объектом. Можно ли ее описать при помощи этих конструкций? Да, можно.
Интерфейс объекта, который может быть вызван, называется callable
. Для того, чтобы указать сигнатуру вызова объекта, нужно в ()
указать параметры и их типы, а через :
(не через =>
) указать возвращаемое значение. В callable
можно указать больше чем одну сигнатуру вызова, таким образом получить описание перегрузок.
Задания
Last updated
Was this helpful?