Простое объяснение перегрузки функций в TypeScript

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

Посмотрим, как она работает.

1. Сигнатура функции

Рассмотрим функцию, которая возвращает сообщение Hello конкретному человеку:

Вышеупомянутая функция принимает 1 аргумент типа string: имя человека. Вызвать функцию довольно просто:

Что, если вы хотите сделать функцию greet() более гибкой? Например, сделайте так, чтобы она дополнительно принимала список лиц, которых нужно поприветствовать.

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

Как реализовать такую функцию? Есть 2 подхода. Первый подход прост и включает в себя изменение сигнатуры функции напрямую путем обновления типа параметра и возвращаемого значения. Вот как выглядит greet() с обновлением типа параметра и возвращаемого значения:

Теперь, вы можете вызывать greet() двумя способами:

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

2. Перегрузка функции

Второй подход — использовать перегрузку функции. Я рекомендую его, когда сигнатура функции относительно сложна и включает несколько типов.

Внедрение перегрузки на практике требует определения так называемых перегрузки сигнатуры и имплементации сигнатуры.

Перегрузка сигнатуры (оverload signatures) определяет параметры и типы возвращаемых данных функции и не имеет тела. Функция может иметь несколько перегрузок сигнатуры: в соответствии с различными способами вызова функции.

Имплементация сигнатуры (іmplementation signature), с другой стороны, также имеет типы параметров и тип возвращаемого значения, а также тело, реализующее функцию. Реализация сигнатуры может быть только одна. Преобразуем функцию greet(), чтобы использовать перегрузку функции:

Функция greet() имеет 2 перегрузки сигнатуры и одну имплементацию. Каждая перегрузка описывает один из способов вызова функции. В случае функции greet() вы можете вызвать ее двумя способами: со строковым аргументом или с массивом строковых аргументов.

Имплементация сигнатуры function greet(person: unknown): unknown { … } содержит логику работы функции. Теперь, как и раньше, вы можете вызывать greet() с аргументами типа строка или массив строк:

2.1 Перегрузка сигнатуры является callable

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

Результат:

В приведенном выше примере вы не можете вызывать функцию greet() с аргументом типа unknown ( greet(someValue)), даже если имплементация сигнатуры принимает аргумент unknown.

2.2 Имплементация сигнатуры должна быть общей

Имейте в виду, что тип имплементации сигнатуры должен быть достаточно общим, чтобы включать перегрузку сигнатуры. В противном случае TypeScript не примет перегрузку сигнатуры. Например, если вы измените тип возвращаемого значения имплементации сигнатуры с unknown на string:

Такая перегрузка сигнатуры несовместима с ее имплементацией.

Тогда перегрузка function greet(persons: string[]): string[] помечается как несовместимая с function greet(person: unknown): string.

Тип String возвращаемого значения имплементации недостаточно общий, чтобы быть совместимым с типом string[] перегрузки сигнатуры.

3. Перегрузка методов

В предыдущих примерах перегрузка применялась к обычной функции. Но вы также можете перегрузить и методы! Во время перегрузки метода перегрузка сигнатуры и ее имплементация теперь являются частью класса. Например, давайте реализуем класс Greeter с перегруженным методом greet():

Класс Greeter содержит перегрузку метода greet(): 2 перегрузки сигнатуры описывающие то, как метод может быть вызван, и имплементацию, содержащую соответствующую реализацию.

Благодаря перегрузке метода вы можете вызывать hi.greet() двумя способами: используя в качестве аргумента строку или массив строк.

4. Когда использовать перегрузку функций

Перегрузка функций при правильном использовании может значительно повысить удобство использования функций, которые можно вызывать разными способами. Это особенно полезно во время автозаполнения: вы перечисляете все возможные перегрузки в виде отдельных записей в автозаполнении.

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

Достаточно использовать необязательные параметры в сигнатуре функции:

5. Вывод

Перегрузка функций в TypeScript позволяет определять функции, которые можно вызывать разными способами.
Использование перегрузки функций требует определения сигнатур перегрузки: набора функций с параметрами и возвращаемыми типами, но без тела. Эти сигнатуры указывают, как должна быть вызвана функция.

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

Автор: Dmitri Pavlutin

Источник: dmitripavlutin.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии запрещены.