Аннотация функции
У параметров и возвращаемого значения указываются типы:
function add(a: number, b: number): number {
return a + b;
}
const result: number = add(3, 4); // 7
Если функция ничего не возвращает — тип void:
function log(message: string): void {
console.log(message);
}
Выведение возвращаемого типа
TypeScript может сам вывести возвращаемый тип, но для публичных функций лучше указывать его явно — это часть контракта и защита от случайного возврата не того значения:
// Лучше явно
function isAdmin(user: User): boolean {
return user.role === "admin";
}
// Плохо: случайно вернём undefined, и TypeScript это разрешит
function isAdmin(user: User) {
if (user.role === "admin") {
return true;
}
// забыли return false — тип станет boolean | undefined
}
Необязательные параметры и значения по умолчанию
function greet(name: string, greeting: string = "Привет"): string {
return `${greeting}, ${name}!`;
}
greet("Анна"); // Привет, Анна!
greet("Анна", "Здравствуй"); // Здравствуй, Анна!
Необязательный параметр (без значения по умолчанию) помечается
? и должен идти после обязательных:
function log(message: string, level?: string): void {
console.log(`[${level ?? "INFO"}] ${message}`);
}
log("Запущено"); // [INFO] Запущено
log("Ошибка", "ERROR"); // [ERROR] Ошибка
Остаточные параметры (rest)
Когда аргументов может быть сколько угодно — ...args:
function sumAll(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0);
}
sumAll(1, 2, 3, 4); // 10
sumAll(); // 0
Реальный кейс — логирование с тегами:
function debug(tag: string, ...args: unknown[]): void {
console.debug(`[${tag}]`, ...args);
}
debug("api", "запрос", { url: "/users", method: "GET" });
Стрелочные функции и тип функции как значение
Стрелочные функции типизируются так же:
const multiply = (a: number, b: number): number => a * b;
Тип функции можно вынести в alias и переиспользовать:
type MathOp = (a: number, b: number) => number;
const add: MathOp = (a, b) => a + b; // типы a и b выводятся
const divide: MathOp = (a, b) => a / b;
const modulo: MathOp = (a, b) => a % b;
function apply(op: MathOp, x: number, y: number): number {
return op(x, y);
}
apply(add, 10, 3); // 13
apply(divide, 10, 3); // 3.33
Кейс: тип колбэка в событийном API
type ClickHandler = (event: { target: HTMLElement; x: number; y: number }) => void;
function onClick(handler: ClickHandler): void {
// ...
}
onClick((e) => console.log(e.target, e.x, e.y));
Перегрузка функций
Когда функция возвращает разные типы в зависимости от аргументов, описывают несколько сигнатур. Реализация — одна, с объединением типов:
function format(value: number): string;
function format(value: string): string;
function format(value: number | string): string {
return typeof value === "number"
? value.toFixed(2)
: value.toUpperCase();
}
format(3.1415); // "3.14" — TS знает, что вернётся string
format("hi"); // "HI"
// format(true); // Ошибка: нет подходящей сигнатуры
Реальный кейс: перегрузка для API-клиента
declare function request(path: string): Promise<unknown>;
function fetchUser(id: number): Promise<User>;
function fetchUser(ids: number[]): Promise<User[]>;
function fetchUser(idOrIds: number | number[]): Promise<User | User[]> {
if (Array.isArray(idOrIds)) {
return request("/users?id=" + idOrIds.join(",")) as Promise<User[]>;
}
return request("/users/" + idOrIds) as Promise<User>;
}
const one = fetchUser(1); // Promise<User>
const many = fetchUser([1, 2]); // Promise<User[]>
Async-функции
Возвращаемое значение async-функции оборачивается в
Promise<T>:
async function fetchUser(id: number): Promise<User> {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
async function fetchAll(): Promise<User[]> {
const [a, b] = await Promise.all([fetchUser(1), fetchUser(2)]);
return [a, b];
}
Типизация ошибок
TypeScript не типизирует исключения — в catch всегда
unknown (при useUnknownInCatchVariables):
try {
await fetchUser(1);
} catch (err) {
// err: unknown
if (err instanceof Error) {
console.log(err.message);
}
}
this в функциях
В обычных функциях тип this можно указать первым параметром
(он не передаётся в рантайме, нужен только компилятору):
interface Button {
el: HTMLElement;
label: string;
render(this: Button): void;
}
const btn: Button = {
el: document.createElement("button"),
label: "OK",
render() {
this.el.textContent = this.label; // TS знает, что такое this
},
};
Кейс: типобезопасный debounce
Утилита debounce с сохранением типов исходной функции —
классический пример применения дженериков (подробнее в главе 6), но даже без
них видна польза типизации колбэков:
function debounce<T extends (...args: any[]) => void>(
fn: T,
delay: number,
): (...args: Parameters<T>) => void {
let timer: ReturnType<typeof setTimeout>;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
const onSearch = debounce((query: string) => {
console.log("Ищу:", query);
}, 300);
onSearch("Type"); // OK
// onSearch(42); // Ошибка: ожидается string
Типичные ошибки
1. Не тот порядок необязательных параметров
function f(a: string, b?: number, c: string): void {}
// ^^^^^^^^
// Ошибка: обязательный параметр после необязательного
2. Забыли вернуть значение
function isAdmin(user: User): boolean {
if (user.role === "admin") {
return true;
}
// забыли return — TypeScript с явным типом подсветит
}
3. Тип Function вместо конкретной сигнатуры
// Плохо: любая функция подойдёт
function onClick(handler: Function): void { ... }
// Хорошо: конкретная сигнатура
function onClick(handler: () => void): void { ... }
Практика
- Напишите функцию
isAdult(age: number): booleanс явным возвратом. - Сделайте стрелочную функцию
squareс типом(n: number) => number. - Реализуйте функцию
clamp(value, min, max)с параметрами по умолчанию дляminиmax. - Опишите перегруженную функцию
parseInput(value: string), которая возвращаетnumber, если строка — число, иначеstring. - Напишите
async-функцию, которая параллельно загружает двух пользователей и возвращает массив.
Итог
Мы разобрали типизацию параметров и возвращаемых значений, параметры по
умолчанию и rest-параметры, функциональные типы, перегрузку и работу с
async/await. В следующей главе — классы и
модификаторы доступа.