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

0 10

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

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

Содержание статьи:

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

JavaScript function greet(person: string): string { return `Hello, ${person}!`; }

123 function greet(person: string): string {  return `Hello, ${person}!`;}

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

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

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

JavaScript greet(‘World’); // ‘Hello, World!’

1 greet(‘World’); // ‘Hello, World!’

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

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

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

JavaScript function greet(person: string | string[]): string | string[] { if (typeof person === ‘string’) { return `Hello, ${person}!`; } else if (Array.isArray(person)) { return person.map(name => `Hello, ${name}!`); } throw new Error(‘Unable to greet’); }

12345678 function greet(person: string | string[]): string | string[] {  if (typeof person === ‘string’) {    return `Hello, ${person}!`;  } else if (Array.isArray(person)) {    return person.map(name => `Hello, ${name}!`);  }  throw new Error(‘Unable to greet’);}

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

JavaScript greet(‘World’); // ‘Hello, World!’ greet([‘Jane’, ‘Joe’]); // [‘Hello, Jane!’, ‘Hello, Joe!’]

12 greet(‘World’);          // ‘Hello, World!’greet([‘Jane’, ‘Joe’]); // [‘Hello, Jane!’, ‘Hello, Joe!’]

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

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

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

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

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

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

JavaScript // Overload signatures function greet(person: string): string; function greet(persons: string[]): string[]; // Implementation signature function greet(person: unknown): unknown { if (typeof person === ‘string’) { return `Hello, ${person}!`; } else if (Array.isArray(person)) { return person.map(name => `Hello, ${name}!`); } throw new Error(‘Unable to greet’); }

12345678910111213 // Overload signaturesfunction greet(person: string): string;function greet(persons: string[]): string[]; // Implementation signaturefunction greet(person: unknown): unknown {  if (typeof person === ‘string’) {    return `Hello, ${person}!`;  } else if (Array.isArray(person)) {    return person.map(name => `Hello, ${name}!`);  }  throw new Error(‘Unable to greet’);}

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

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

JavaScript greet(‘World’); // ‘Hello, World!’ greet([‘Jane’, ‘Joe’]); // [‘Hello, Jane!’, ‘Hello, Joe!’]

12 greet(‘World’);          // ‘Hello, World!’greet([‘Jane’, ‘Joe’]);  // [‘Hello, Jane!’, ‘Hello, Joe!’]

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

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

JavaScript greet(‘World’); // Overload signature callable greet([‘Jane’, ‘Joe’]); // Overload signature callable const someValue: unknown = ‘Unknown’; greet(someValue); // Implementation signature NOT callable

12345 greet(‘World’);         // Overload signature callablegreet([‘Jane’, ‘Joe’]); // Overload signature callable const someValue: unknown = ‘Unknown’;greet(someValue);       // Implementation signature NOT callable

Результат:

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

Фреймворк VUE JS: быстрый старт, первые результаты

Получите бесплатный курс и узнайте, как создать веб-приложение на трендовой Frontend-технологии VUE JS с полного нуля

JavaScript No overload matches this call. Overload 1 of 2, ‘(person: string): string’, gave the following error. Argument of type ‘unknown’ is not assignable to parameter of type ‘string’. Overload 2 of 2, ‘(persons: string[]): string[]’, gave the following error. Argument of type ‘unknown’ is not assignable to parameter of type ‘string[]’.

12345 No overload matches this call.  Overload 1 of 2, ‘(person: string): string’, gave the following error.    Argument of type ‘unknown’ is not assignable to parameter of type ‘string’.  Overload 2 of 2, ‘(persons: string[]): string[]’, gave the following error.    Argument of type ‘unknown’ is not assignable to parameter of type ‘string[]’.

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

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

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

JavaScript // Overload signatures function greet(person: string): string; function greet(persons: string[]): string[];

123 // Overload signaturesfunction greet(person: string): string;function greet(persons: string[]): string[];

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

JavaScript // Implementation signature function greet(person: unknown): string { // … throw new Error(‘Unable to greet’); }

12345 // Implementation signaturefunction greet(person: unknown): string {  // …  throw new Error(‘Unable to greet’);}

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

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

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

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

JavaScript class Greeter { message: string; constructor(message: string) { this.message = message; } // Overload signatures greet(person: string): string; greet(persons: string[]): string[]; // Implementation signature greet(person: unknown): unknown { if (typeof person === ‘string’) { return `${this.message}, ${person}!`; } else if (Array.isArray(person)) { return person.map(name => `${this.message}, ${name}!`); } throw new Error(‘Unable to greet’); } }

123456789101112131415161718192021 class Greeter {  message: string;   constructor(message: string) {    this.message = message;  }   // Overload signatures  greet(person: string): string;  greet(persons: string[]): string[];   // Implementation signature  greet(person: unknown): unknown {    if (typeof person === ‘string’) {      return `${this.message}, ${person}!`;    } else if (Array.isArray(person)) {      return person.map(name => `${this.message}, ${name}!`);    }    throw new Error(‘Unable to greet’);  }}

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

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

JavaScript const hi = new Greeter(‘Hi’); hi.greet(‘Angela’); // ‘Hi, Angela!’ hi.greet([‘Pam’, ‘Jim’]); // [‘Hi, Pam!’, ‘Hi, Jim!’]

1234 const hi = new Greeter(‘Hi’); hi.greet(‘Angela’);       // ‘Hi, Angela!’hi.greet([‘Pam’, ‘Jim’]); // [‘Hi, Pam!’, ‘Hi, Jim!’]

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

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

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

JavaScript // Not recommended function myFunc(): string; function myFunc(param1: string): string; function myFunc(param1: string, param2: string): string; function myFunc(…args: string[]): string { // implementation… }

1234567 // Not recommendedfunction myFunc(): string;function myFunc(param1: string): string;function myFunc(param1: string, param2: string): string;function myFunc(…args: string[]): string {  // implementation…}

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

JavaScript // OK function myFunc(param1?: string, param2: string): string { // implementation… }

1234 // OKfunction myFunc(param1?: string, param2: string): string {  // implementation…}

5. Вывод

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

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

Автор: Dmitri Pavlutin

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

Оставьте ответ