ПрограммированиеFullstack разработчик

Как реализовать и правильно типизировать функцию обратного вызова (callback) с параметрами, которые могут быть опциональными или иметь значения по умолчанию? Какие сложности могут возникнуть и как их избежать?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

История вопроса:

Callback-функции — распространённая практика в JS и TS для асинхронного программирования и делегирования ответственности. В TypeScript типизация таких функций — важная часть обеспечения безопасности, особенно если параметры могут быть опциональными или иметь дефолтные значения.

Проблема:

В динамическом JS отсутствие типизации callback-аргументов приводит к ошибкам передачи значения, путанице с undefined и неправильному order параметров. В TypeScript типизация требуется для избежания подобных проблем, но снаружи сложно соблюсти все нюансы, связанные с опциональностью, порядком и дефолтными значениями.

Решение:

Явно указывать типы всех параметров, опциональные параметры обозначать вопросительным знаком, а значения по умолчанию — указывать прямо при объявлении функции, и не забывать корректно описывать их в типе.

Пример кода:

function fetchData( url: string, callback: (data: any, error?: Error) => void ) { // ... } // Callback с опциональным параметром error fetchData('/api', (data, error) => { if (error) { // обработка } else { // success } }); // Callback с параметром по умолчанию function process( cb: (x: number, y?: number) => void = (x, y = 10) => { /* ... */ } ) { /* ... */ }

Ключевые особенности:

  • Для опциональных параметров используется знак "?".
  • Для дефолтных значений указывается значение по умолчанию в определении функции.
  • Типизация облегчает поддержку кода и снижает количество ошибок.

Вопросы с подвохом.

Обязан ли потребитель callback явно учитывать все параметры, включая опциональные?

Нет, он может опускать опциональные параметры, и TypeScript не выдаст ошибку — обработка происходит корректно благодаря синтаксису вопросительного знака.

Можно ли сделать первый параметр в callback опциональным, а второй — обязательным?

Нет. Опциональные параметры всегда должны идти в конце списка аргументов. Нарушение порядка приведёт к ошибке типизации.

Что произойдёт, если не обозначить опциональность параметра, но не передать его в месте вызова?

TypeScript выдаст ошибку — если параметр обязательный, он должен быть передан. Только опциональные или с дефолтом могут быть опущены.

Типовые ошибки и анти-паттерны

  • Нарушение порядка опциональных и обязательных параметров (сначала обязательные, потом — опциональные).
  • Отсутствие явного указания типов или "any" — приводит к потере преимуществ TypeScript.
  • Попытки передать undefined вместо значения и ожидание срабатывания дефолта (срабатывает только при отсутствии аргумента).

Пример из жизни

Негативный кейс

Обозначили второй аргумент callback обязательным, а в вызове не передали его. Получили ошибку компиляции.

Плюсы:

  • Быстро и просто написанный код без уточнений.

Минусы:

  • Не компилируется.
  • Потеря гибкости и запутанная ответственность.

Позитивный кейс

Типизировали callback с опциональным параметром:

(cb: (x: number, y?: number) => void)

либо задали дефолт:

f = (x: number, y = 10) => { ... }

Плюсы:

  • Гарантия отсутствия ошибок при вызове callbacks.
  • Читабельность и поддерживаемость.

Минусы:

  • Нужно быть внимательным к порядку параметров.