关于javascript:TypeScript中函数重载写法你在第几层

3次阅读

共计 3951 个字符,预计需要花费 10 分钟才能阅读完成。

作者:dmitripavlutin
译者:前端小智
起源:dmitripavlutin

有幻想,有干货,微信搜寻【大迁世界】关注这个在凌晨还在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

大多数函数承受一组固定的参数。

但有些函数能够承受可变数量的参数,不同类型的参数,甚至能够依据你调用函数的形式返回不同的类型。为了正文这样的函数,TypeScript 提供了函数重载性能。

1. 函数签名

咱们先来思考一个函数,它返回给一个特定的人的问候信息。

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

下面的函数承受 1 个字符类型的参数:人的名字。调用该函数是非常简单的:

greet('World'); // 'Hello, World!'

如果你想让 greet()函数更加灵便,怎么办?例如,让它另外承受一个要问候的人的列表。

这样的函数将承受一个字符串或字符串数组作为参数,并返回一个字符串或字符串数组。

如何对这样的函数进行正文?有 2 种办法。

第一种办法很简略,就是通过更新参数和返回类型间接批改函数签名。上面重构后 greet() 的样子:

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():

greet('World');          // 'Hello, World!'
greet(['小智', '大冶']); // ['Hello, 小智!', 'Hello, 大冶!']

间接更新函数签名以反对多种调用形式是一种常见的好办法。

然而,在某些状况下,咱们可能须要采纳另一种办法,别离定义你的函数能够被调用的所有形式。这种办法被称为 函数重载

2. 函数重载

第二种办法是应用函数重载性能。当函数签名绝对简单且波及多种类型时,我举荐应用这种办法。

定义函数重载须要定义重载签名和一个实现签名。

重载签名定义函数的形参和返回类型,没有函数体。一个函数能够有多个重载签名: 对应于调用该函数的不同形式。

另一方面,实现签名还具备参数类型和返回类型,而且还有实现函数的主体,且只能有一个实现签名。

// 重载签名
function greet(person: string): string;
function greet(persons: string[]): string[];
 
// 实现签名
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');
}

greet() 函数有两个重载签名和一个实现签名。

每个重载签名都形容了能够调用该函数的一种形式。就 greet()函数而言,咱们能够用两种形式调用它:用一个字符串参数,或用一个字符串数组参数。

实现签名 function greet(person: unknown): unknown {...} 蕴含了该函数如何工作的适当逻辑。

当初,和下面一样,能够用字符串或字符串数组类型的参数来调用 greet()

greet('World');          // 'Hello, World!'
greet(['小智', '大冶']); // ['Hello, 小智!', 'Hello, 大冶!']

2.1 重载签名是可调用的

尽管实现签名实现了函数行为,然而它不能间接调用。只有重载签名是可调用的。

greet('World');          // 重载签名可调用
greet(['小智', '大冶']); // 重载签名可调用

const someValue: unknown = 'Unknown';
greet(someValue);       // Implementation signature NOT callable

// 报错
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[]'.

在下面的示例中,即便实现签名承受 unknown 参数,也不能应用类型为 unknown (greet(someValue)) 的参数调用 greet() 函数。

2.1 实现签名必须是通用的

// 重载签名
function greet(person: string): string;
function greet(persons: string[]): string[]; 
// 此重载签名与其实现签名不兼容。// 实现签名
function greet(person: unknown): string {
  // ...
  throw new Error('Unable to greet');
}

重载签名函数 greet(person: string[]): string[] 被标记为与 greet(person: unknown): string 不兼容。

实现签名的 string 返回类型不够通用,不能与重载签名的 string[] 返回类型兼容。

3. 办法重载

尽管在后面的例子中,函数重载被利用于一个一般函数。然而咱们也能够重载一个办法

在办法重载区间,重载签名和实现签名都是类的一部分了。

例如,咱们实现一个 Greeter类,有一个重载办法greet()

class Greeter {
  message: string;
 
  constructor(message: string) {this.message = message;}
 
  // 重载签名
  greet(person: string): string;
  greet(persons: string[]): string[];
 
  // 实现签名
  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():应用一个字符串或应用一个字符串数组作为参数。

const hi = new Greeter('Hi');
 
hi.greet('小智');       // 'Hi, 小智!'
hi.greet(['王大冶', '大冶']); // ['Hi, 王大冶!', 'Hi, 大冶!']

4. 何时应用函数重载

函数重载,如果应用切当,能够大大增加可能以多种形式调用的函数的可用性。这在主动补全时特地有用: 咱们会在主动补全中列出所有可能的重载记录。

然而,在某些状况下,倡议不要应用函数重载,而应该应用函数签名。

例如,不要对可选参数应用函数重载:

// 不举荐做法
function myFunc(): string;
function myFunc(param1: string): string;
function myFunc(param1: string, param2: string): string;
function myFunc(...args: string[]): string {// implementation...}

在函数签名中应用可选参数是足够的:

// 举荐做法
function myFunc(param1?: string, param2: string): string {// implementation...}

5. 总结

TypeScript 中的函数重载让咱们定义以多种形式调用的函数。

应用函数重载须要定义重载签名:一组带有参数和返回类型的函数,但没有主体。这些签名表明应该如何调用该函数。

此外,你必须写出函数的正确实现(实现签名):参数和返回类型,以及函数体。请留神,实现签名是不可调用的。

除了惯例的函数之外,类中的办法也能够重载。


代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

原文:https://dmitripavltin.com/typ…

交换

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588… 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

正文完
 0