Перейти к содержанию
Educora
Начальный15 мин3 / 8

Типизированные функции

Указывай типы параметров и возвращаемых значений функций, используй необязательные параметры, параметры по умолчанию и rest-параметры, описывай типы функций.

Проверь себя
В этом уроке ты узнаешь
  • Указывать типы параметров и возвращаемого значения
  • Использовать необязательные параметры, параметры по умолчанию и rest-параметры
  • Записывать типы функций вроде (a: number) => number и понимать контекстную типизацию
  • Знать, что означают типы void и never

Функция — это своего рода договор: что она принимает и что возвращает. В JavaScript этот договор живёт лишь в памяти программиста или в комментариях, а комментарии быстро устаревают. В TypeScript договор записан прямо в заголовке функции, и компилятор проверяет, что он соблюдается при каждом вызове, — и когда ты пишешь функцию, и когда её используешь.

Параметры и возвращаемое значение

Тип каждого параметра пишут после его имени через двоеточие. Тип возвращаемого значения ставят после скобок. Функция ниже считает чаевые в ресторане:

TypeScript
function calculateTip(bill: number, percent: number): number {
  return (bill * percent) / 100;
}

const tip = calculateTip(40, 15);
console.log(`Tip: ${tip} AZN`);
Ожидаемый результат
Tip: 6 AZN

Компилятор проверяет обе стороны договора. Вызывающий код должен передать все аргументы нужных типов, а тело функции — вернуть обещанный тип:

TypeScript
function calculateTip(bill: number, percent: number): number {
  return (bill * percent) / 100;
}

calculateTip(40);

function isAdult(age: number): boolean {
  if (age >= 18) {
    return 'yes';
  }
  return false;
}
Text
tip.ts:5:1 - error TS2554: Expected 2 arguments, but got 1.

5 calculateTip(40);
  ~~~~~~~~~~~~

  tip.ts:1:37
    1 function calculateTip(bill: number, percent: number): number {
                                          ~~~~~~~~~~~~~~~
    An argument for 'percent' was not provided.

tip.ts:9:5 - error TS2322: Type 'string' is not assignable to type 'boolean'.

9     return 'yes';
      ~~~~~~
Первая ошибка — у вызывающего кода, вторая — в самой функции. Компилятор даже сообщает, какой аргумент забыт.

Необязательные параметры, значения по умолчанию и rest

  • Необязательный параметр отмечают ? после имени: greeting?: string. На самом деле его тип — string | undefined, то есть его можно не передавать.
  • Параметр со значением по умолчанию (currency = 'AZN') получает тип из этого значения — здесь string. Если аргумент не передан, используется значение по умолчанию.
  • Rest-параметр (...numbers: number[]) собирает любое количество аргументов в массив.
  • Необязательные параметры должны идти после обязательных.
TypeScript
function greet(name: string, greeting?: string): string {
  return `${greeting ?? 'Hello'}, ${name}!`;
}

function price(amount: number, currency = 'AZN'): string {
  return `${amount.toFixed(2)} ${currency}`;
}

function sum(...numbers: number[]): number {
  return numbers.reduce((total, n) => total + n, 0);
}

console.log(greet('Murad'));
console.log(greet('Murad', 'Salam'));
console.log(price(12.5), '|', price(12.5, 'USD'));
console.log(sum(1, 2, 3), sum());
Ожидаемый результат
Hello, Murad!
Salam, Murad!
12.50 AZN | 12.50 USD
6 0
Оператор ?? подставляет 'Hello', если greeting не передан.

Поскольку необязательный параметр может быть undefined, TypeScript не даёт использовать его без проверки. В greet мы подставили запасное значение через ??; если забыть об этом, получится вот что:

TypeScript
function shout(name: string, greeting?: string): string {
  return `${greeting.toUpperCase()}, ${name}!`;
}
Text
shout.ts:2:13 - error TS18048: 'greeting' is possibly 'undefined'.

2   return `${greeting.toUpperCase()}, ${name}!`;
              ~~~~~~~~

Типы функций

В JavaScript функции — обычные значения: их можно сохранять в переменные и передавать в другие функции как аргументы. Значит, у функции тоже есть тип. Тип функции записывают стрелочным синтаксисом: (a: number, b: number) => number — «функция, которая принимает два числа и возвращает число». Такому типу удобно дать имя через type.

TypeScript
type Operation = (a: number, b: number) => number;

const add: Operation = (a, b) => a + b;
const multiply: Operation = (a, b) => a * b;

function calculate(x: number, y: number, op: Operation): number {
  return op(x, y);
}

console.log(calculate(6, 7, add));
console.log(calculate(6, 7, multiply));
console.log([1, 2, 3].map((n) => n * 10));
Ожидаемый результат
13
42
[ 10, 20, 30 ]

Обрати внимание: в add мы не указали типы a и b, но ошибки нет. Это контекстная типизация (contextual typing): функция записана в переменную типа Operation, поэтому TypeScript знает, что параметры — number. С map то же самое: массив состоит из чисел, поэтому n автоматически получает тип number.

ТипЗначениеПример
voidфункция не возвращает ничего полезногоfunction log(msg: string): void
neverфункция никогда не завершается нормально — например, всегда бросает ошибкуfunction fail(msg: string): never
тип функциипараметры и возвращаемый тип(a: number, b: number) => number

Главное

  • Типы параметров пишут после их имён, а возвращаемый тип — после скобок.
  • Компилятор проверяет количество и типы аргументов, а в теле функции — возвращаемое значение.
  • x?: T — необязательный параметр типа T | undefined; x = значение — значение по умолчанию; ...xs: T[] — rest-параметр.
  • Тип функции записывают со стрелкой: (a: number, b: number) => number; контекстная типизация сама определяет типы параметров.
  • void — ничего не возвращает, never — никогда не завершается нормально.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Что описывает тип (a: number, b: number) => number?