Тип функции
В JavaScript функция — такое же значение, как число или строка. Её кладут в переменную, передают в другую функцию, хранят в массиве. Но какой тип у переменной, в которой лежит функция?
Представьте стену с автоматами на вокзале. Над одним из мест висит табличка «Берёт две монеты, выдаёт стакан», а самого автомата ещё нет. Поставить туда можно любой автомат, который берёт две монеты и выдаёт стакан, — неважно, кто его сделал и что у него внутри. Тип функции — такая табличка без автомата: он описывает, какие параметры функция принимает и что возвращает, а саму функцию подставят позже.
Запись типа функции
Наведите курсор на add в строке const add = (a: number, b: number) => a + b;. Подсказка покажет const add: (a: number, b: number) => number. Часть после двоеточия и есть тип функции. Его можно назвать через type, как любой другой тип:
type Op = (a: number, b: number) => number;
const add: Op = (a: number, b: number) => a + b;
const mul: Op = (x: number, y: number) => x * y;
function apply(op: Op, a: number, b: number): number {
return op(a, b);
}
console.log(apply(add, 2, 3), apply(mul, 2, 3)); // 5 6Разберём запись (a: number, b: number) => number по частям:
- в скобках — параметры с типами, как в сигнатуре функции;
- после стрелки
=>— тип результата: в типе функции его пишут после стрелки, а не после двоеточия; - имена
aиbнужны только читателю: уmulпараметры называютсяxиy, и она всё равно подходит кOp.
Теперь пример по строкам:
type Opдаёт имя табличке: «берёт два числа, возвращает число».addиmul— две разные функции, и обе подходят кOp.- Параметр
op: Opвapplyпринимает любую функцию этого типа. apply(add, 2, 3)вызываетaddи возвращает5, аapply(mul, 2, 3)—6.
Функция не того вида
Если параметры или результат функции не совпадают с табличкой, tsc не даст положить её в переменную:
type Op = (a: number, b: number) => number;
const glue: Op = (a: string, b: string) => a + b; // ✗error TS2322: Type '(a: string, b: string) => string' is not assignable to type 'Op'.Сообщение значит: «функцию типа (a: string, b: string) => string нельзя присвоить типу Op». apply передаст в неё два числа, а функция ждёт строки. В сообщении tsc показывает тип функции в той же записи со стрелкой.
Здесь аналогия с табличкой заканчивается. На табличке автомата не пишут имён для монет. А в типе функции у параметров имена есть, но tsc на них не смотрит: он сравнивает только типы параметров и тип результата.
void в типе функции
В третьей теме функция с аннотацией : void не могла вернуть значение: tsc отвечал ошибкой TS2322. В типе функции void ведёт себя иначе:
type Callback = (n: number) => void;
const saved: number[] = [];
const keep: Callback = (n: number) => saved.push(n);
const r = keep(5);
console.log(r, saved.length); // 1 1Метод push возвращает новую длину массива, поэтому стрелка возвращает число. И всё же она подходит к Callback, а при запуске keep(5) возвращает 1. Но у r тип void, поэтому r + 1 даст ошибку TS2365: результатом такой функции пользоваться нельзя. Передать r в console.log можно — он принимает значение любого типа, — а считать с ним или вызывать его методы tsc не даст.
void в типе функции значит «результат никто не использует», а не «функция ничего не возвращает». Так удобно писать колбэки: метод forEach ждёт функцию с результатом void, и стрелка (n: number) => saved.push(n) подходит к нему, хотя push что-то возвращает. На собеседовании об этом спрашивают так: «Почему функция, которая возвращает число, подходит к типу () => void?»
Частая ошибка
Тип результата записали через двоеточие, как в объявлении функции:
type Op = (a: number, b: number): number; // ✗error TS1005: '=>' expected.Сообщение значит: «ожидалась стрелка =>». Двоеточие перед типом результата пишут в объявлении функции, а в типе функции — стрелку: (a: number, b: number) => number.
Главное
- Тип функции записывают как
(a: number, b: number) => number: параметры с типами, стрелка, тип результата. - К типу функции подходит любая функция с теми же типами параметров и результата; имена параметров не важны.
voidв типе функции значит «результат не используют»: функция, которая возвращает значение, тоже подходит.- В типе функции тип результата пишут после
=>, а не после двоеточия.