Функции

Функции

Технический фундамент типового контракта функции

У функции в TS есть две критичные части контракта:

  • тип входов (параметры, их обязательность, порядок);
  • тип выхода (что вызывающий код гарантированно получит).

Дополнительно важно помнить:

  • перегрузки описывают внешний API, но реализация должна покрывать все сигнатуры;
  • union-параметры требуют narrowing перед специфичными операциями;
  • слишком широкий тип функции быстро "размывает" типовую безопасность по цепочке вызовов.

Почему типизация функций критична

Функции связывают модули между собой. Если у функции неясный контракт, ошибка легко распространяется по всему проекту: передали не тот аргумент, получили неожиданный тип результата, сломали бизнес-логику. TypeScript позволяет явно описать вход и выход функции.

Ключевой момент: функция в TypeScript это контракт параметров + контракт возвращаемого значения.

Проверь себя: почему тип возвращаемого значения так же важен, как тип входных параметров?

Базовая аннотация функции

function sum(a: number, b: number): number {
  return a + b;
}

Здесь:

  • a: number, b: number - типы параметров;
  • : number после скобок - тип результата.

Смотри, что важно: TypeScript часто выводит возвращаемый тип сам, но явная аннотация полезна для публичного API.

Опциональные и дефолтные параметры

function greet(name: string, title?: string): string {
  return title ? `${title} ${name}` : name;
}

function createUser(name: string, role: string = 'user'): string {
  return `${name}:${role}`;
}
  • ? делает параметр необязательным;
  • = задает значение по умолчанию.

Здесь часто путаются: обязательные параметры должны идти раньше опциональных.

Rest-параметры

Когда аргументов может быть много, используют rest.

function total(...values: number[]): number {
  return values.reduce((acc, x) => acc + x, 0);
}

Новый термин: rest-параметр - сбор множества аргументов в массив.

Проверь себя: чем ...values: number[] отличается от параметра values: number[]?

Тип функции через alias

Для переиспользования сигнатуры удобно делать alias.

type Comparator = (a: number, b: number) => number;

const asc: Comparator = (a, b) => a - b;

Это особенно полезно в колбэках и сервисах с одинаковым типом функций.

Перегрузки (overloads)

Когда функция поддерживает несколько форм входа, можно описать перегрузки.

function format(value: number): string;
function format(value: string): string;
function format(value: number | string): string {
  return String(value).trim();
}

Смотри, что важно: сигнатуры перегрузки описывают внешний контракт, а реализация использует объединенный тип.

Реальные микро-сценарии

  1. API-утилита request.

Типы параметров и результата снижают риск неправильного вызова.

  1. Форматтеры дат и цен.

Явные типы гарантируют, что функция не получит неподходящий формат.

  1. Callback-и сортировки.

Сигнатура компаратора защищает от некорректного результата сравнения.

Частые ошибки новичков

  • Забывать тип возвращаемого значения в ключевых функциях.
  • Использовать any в параметрах вместо конкретного или union-типа.
  • Переусложнять перегрузки без реальной необходимости.
  • Смешивать undefined-ветки без явного контракта.

Анти-провал: если функция часто используется в проекте, обязательно зафиксируй ее сигнатуру максимально точно.

Что будет, если изменить входные данные

Если sum получает '2' вместо 2, TypeScript даст ошибку на этапе компиляции. В JS это могло бы привести к строковой конкатенации или NaN в сложной формуле. Явный контракт функции защищает от таких тихих сбоев.

Проверь себя: в каком случае лучше number | string, а в каком лучше оставить строго number и нормализовать вход заранее?

Краткий итог

  • Типизация функций фиксирует входы и выходы, делая API предсказуемым.
  • Опциональные, дефолтные и rest-параметры помогают описывать реальные сценарии вызова.
  • Alias и перегрузки делают код выразительным при сложных интерфейсах.
  • Четкие сигнатуры сильно упрощают поддержку и рефакторинг.
  • Большая часть багов интеграции уходит, когда функции имеют строгий типовой контракт.