Функция в TypeScript это функция JavaScript с типами у параметров и, при желании, у возвращаемого значения. Каждый параметр получает аннотацию, возвращаемый тип пишется после списка параметров, и компилятор сверяет с ними каждый вызов.
Оба неправильных вызова дают ошибки компиляции (TS2345 и TS2554). Комментарии // @ts-expect-error сообщают компилятору, что на следующей строке ожидается ошибка, поэтому остальной файл всё равно выполняется. Удалите один из них и запустите снова, чтобы увидеть настоящее сообщение.
Типы параметров
Каждый параметр записывается как name: Type. В режиме strict, который в TypeScript 7 включён по умолчанию, параметр без аннотации и без контекста для вывода даёт ошибку: Parameter 'x' implicitly has an 'any' type. (TS7006). Так что на практике каждый параметр самостоятельной функции аннотируется.
Типом параметра может быть любой тип: примитивы, массивы, объектные типы, объединения, другие функции.
TypeScript проверяет и количество аргументов. Передать больше или меньше, чем объявлено, это ошибка, в отличие от обычного JavaScript, который заполняет недостающие аргументы undefined и игнорирует лишние. Как сделать параметр опциональным или задать ему значение по умолчанию, описано на странице опциональные параметры.
Возвращаемые типы: указать или вывести
Возвращаемый тип идёт после закрывающей скобки: function f(): Type. Он необязателен. Без него TypeScript выводит тип из каждого return в теле.
Аннотация оправдана, когда функция экспортируется, когда у неё несколько путей возврата или когда она рекурсивная. Тогда ошибка появляется внутри функции, у неверного return, а не у вызывающего кода. Классический случай это ветка, которая забыла вернуть значение:
Компилятор сообщает index.ts(2,32): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. Добавьте в конце return "C";, и код запустится. Без аннотации : string функция скомпилировалась бы с выведенным типом "A" | "B" | undefined, и проблема переместилась бы к тому, кто использует результат.
void: функции, которые ничего не возвращают
У функции, которая только что-то делает (пишет в лог, записывает, изменяет), возвращаемый тип void. Именно его TypeScript выводит, когда нет return со значением, и его можно написать явно.
Эти правила про void удивляют многих:
| Ситуация | Разрешено? |
|---|---|
function f(): void { return 42; } | Нет: Type 'number' is not assignable to type 'void'. (TS2322) |
const f: () => void = () => 42; | Да: значение возвращается, но вызывающий код не должен на него полагаться |
function f(): undefined {} | Да (TypeScript 5.1 и новее) |
Использование результата void-функции в if | Нет: An expression of type 'void' cannot be tested for truthiness. (TS1345) |
Вторая строка так устроена намеренно. Именно поэтому arr.forEach(x => list.push(x)) компилируется, хотя push возвращает число. void в типе функции означает «что бы она ни вернула, это никто не читает». Для функции, которая вообще никогда не возвращает управление (всегда бросает исключение или зацикливается навсегда), возвращаемый тип never.
Стрелочные функции и функциональные выражения
Стрелочные функции и функциональные выражения аннотируются так же. Возвращаемый тип идёт после списка параметров, перед =>.
Без скобок (x, y) => { x, y } это блок без return, и функция возвращает undefined. Правила времени выполнения для стрелочных функций (нет своего this, нет arguments) те же, что в JavaScript; см. стрелочные функции в JavaScript.
Когда функция написана прямо в аргументе, её параметры обычно вообще не аннотируют. TypeScript знает, что получает колбэк, из функции, в которую он передаётся (контекстная типизация): в [1, 2].map(n => n * 2) у n уже тип number. Запись типа функции как значения, (n: number) => string, описана на странице типы функций.
Возврат нескольких значений
Функция возвращает одно значение, поэтому верните объект или кортеж и деструктурируйте его.
Кортежному возвращаемому типу нужна аннотация. Без неё [a, b] выводится как string[]: деструктуризация по-прежнему работает, но тип больше не говорит, что элементов ровно два.
Async-функции
async-функция всегда возвращает Promise. Аннотируйте возвращаемый тип как Promise<T>, где T это то, что функция возвращает внутри.
async function loadScore(id: number): Promise<number> {
await new Promise((resolve) => setTimeout(resolve, 10));
return id * 10;
}
async function main(): Promise<void> {
const score = await loadScore(4); // score: number
console.log("score", score);
}
main();
Запись async function f(): number даёт ошибку: The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<number>'? (TS1064).
Параметр this
JavaScript определяет this в момент вызова. TypeScript позволяет объявить, каким должен быть this, через фиктивный первый параметр с именем this. Он удаляется из скомпилированного JavaScript, и вызывающий код его не передаёт.
interface Counter {
count: number;
}
function increment(this: Counter, by: number): void {
this.count += by;
}
const c = { count: 0, increment };
c.increment(2); // fine: this is c
increment(2);
// error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Counter'.
Без параметра this внутри самостоятельной функции this имеет неявный тип any, и строгий режим сообщает 'this' implicitly has type 'any' because it does not have a type annotation. (TS2683). В методах классов this уже типизирован как экземпляр класса, поэтому этот параметр полезен в основном для самостоятельных функций, прикреплённых к объектам, и для колбэков, которые библиотеки вызывают с определённым this.
Часто задаваемые вопросы
Как указать возвращаемый тип функции в TypeScript?
Напишите двоеточие и тип после списка параметров: function total(a: number, b: number): number { ... }. У стрелочной функции он стоит там же: const total = (a: number, b: number): number => a + b;. Если его не указать, TypeScript выведет возвращаемый тип из операторов return.
Нужно ли всегда аннотировать возвращаемый тип в TypeScript?
Это необязательно, потому что возвращаемый тип выводится. Аннотируйте его у экспортируемых функций и у функций с несколькими путями return: аннотация фиксирует контракт, и неверный return тогда обнаруживается внутри функции, а не у какого-то далёкого вызывающего кода.
Чем void отличается от undefined в TypeScript?
void означает «вызывающий код не должен использовать возвращаемое значение». undefined это конкретный тип значения. Функция, объявленная как (): void, не может возвращать значение, но тип колбэка () => void принимает функцию, которая что-то возвращает, и результат просто игнорируется. Используйте void для функций, которые ничего не возвращают, а undefined только когда вызывающий код действительно сравнивает результат с undefined.
Как вернуть несколько значений из функции TypeScript?
Верните объект ({ min: number; max: number }) или кортеж ([number, number]) и деструктурируйте его в месте вызова. Объекты понятнее, когда значения означают разное; кортежи хорошо читаются для коротких пар вроде [value, setValue].
Какой возвращаемый тип у async-функции в TypeScript?
Всегда Promise. У async-функции, которая возвращает number, возвращаемый тип Promise<number>, а если написать ей : number, будет ошибка компиляции (TS1064). Функция, которая ничего не возвращает, имеет тип Promise<void>.