Typescript: Опциональные параметры в функциях

В этом уроке мы разберем опциональные параметры в функциях.

Использование опциональных параметров в функциях

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

Например, функция split() разбивает строку на массив строк по разделителю:

function split(str: string, separator?: string)

split('hexlet');
split('hexlet,code-basics', ',');

В таком случае реальный тип переменной separator будет string | undefined (string или undefined).

Другой вариант задать опциональный параметр — присвоить значение по умолчанию:

// Знака вопроса больше нет, так как есть значение по умолчанию
function split(str: string, separator: string = ',') {
  // ...
}

split('hexlet');
split('hexlet,code-basics', ',');

Разработчики пытаются применять эту логику к колбекам, но сталкиваются с ошибками. Разберем, почему так происходит.

Колбек функции

Представим функцию filter(), которая фильтрует числовые массивы по переданному предикату:

// Необязательный параметр index
function filter(coll: number[], callback: (arg: number, index?: number) => boolean) {
  const result: number[] = [];
  coll.forEach((n, index) => {
    // Здесь он передается в колбек
    if (callback(n, index)) {
      result.push(n);
    }
  });
  return result;
}

Как и во встроенном методе filter(), в этой функции колбек принимает вторым параметром индекс обрабатываемого элемента массива. Обычно его не используют, но иногда фильтрация массива делается на основе индексов. И в этой ситуации его указывают. Для этого мы пометили этот параметр как необязательный.

Проблема определения выше в том, что оно не работает:

// Выполнится без ошибок
filter([1, 2], (n) => n > 1);
// Object is possibly 'undefined'
filter([1, 2], (n, index) => index > n);

В данном случае ошибка обозначает, что из-за необязательности внутри колбека в теории может оказаться undefined. Хотя по смыслу это происходить не может, так как индекс всегда определен.

Чтобы решить эту ситуацию, нужно отказаться от опциональности:

function filter(coll: number[], callback: (arg: number, index: number) => boolean) {
  // ...
}

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

В примере выше аргументом передается функция (n) => n > 1, а вызывается она как callback(n, index). Это приводит к игнорированию index, при этом никаких ошибок типов не возникает.

Задание

Реализуйте функцию map(). Она должна принимать на вход массив чисел и колбек, который будет использоваться для преобразования каждого числа из массива в другое число. Функция возвращает массив с новыми числами:

map([3, 9], (n) => n - 3);
// [0, 6]

map([8, 9], (n) => n + 8);
// [16, 17]

Параметры функции:

  1. Массив чисел
  2. Анонимная функция, которая принимает на вход число и возвращает число. У этой функции есть необязательный параметр — индекс элемента в массиве
map([8, 9], (n, index) => index + n);
// [8, 10]
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

  • Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются
Loading...

Ваше упражнение проверяется по этим тестам

1import map from './index';
2
3test('map', () => {
4  const result = map([], (n: number) => n + 3);
5  expect(result).toEqual([]);
6
7  const result2 = map([3, 9], (n: number) => n - 3);
8  expect(result2).toEqual([0, 6]);
9
10  const result3 = map([8, 9], (n: number) => n + 8);
11  expect(result3).toEqual([16, 17]);
12
13  const result4 = map([10, 10, 10], (n: number, index) => n + index);
14  expect(result4).toEqual([10, 11, 12]);
15});
16

Решение учителя откроется через:

20:00
waiting_clock