参考

https://ts.xcatliu.com/basics/type-of-function.html
https://jkchao.github.io/typescript-book-chinese/typings/functions.html
函数是JavaScript中传递数据的主要手段。TypeScript允许你指定函数的输入和输出值的类型。

函数(已实现)注解(参数和返回)

类型注解是你描述现有实现类型的一种方式

参数类型注解

当你声明一个函数时,你可以在每个参数后面添加类型注解,以声明该函数接受哪些类型的参数。参数类型注解位于参数名称之后。

  1. // Parameter type annotation
  2. function greet(name: string) {
  3. console.log("Hello, " + name.toUpperCase() + "!!");
  4. }

当一个参数有类型注解时,该函数的参数将被检查。
即使你的参数上没有类型注解,TypeScript 仍然会检查你是否传递了正确数量的参数。

返回类型注解

你也可以添加返回类型注解。返回类型注解出现在参数列表的后面。

  1. function getFavoriteNumber(): number {
  2. return 26;
  3. }

与变量类型注解一样,你通常不需要返回类型注解,因为TypeScript将根据其返回语句推断出函数的返回类型。上面的例子中的类型注解并没有改变任何东西。一些代码库会明确指定一个返回类型,以达到文档的目的,防止意外的改变,或者只是出于个人的偏好。

匿名函数

匿名函数与函数声明有一点不同。当一个函数出现在TypeScript可以确定它如何被调用的地方时,该函数的参数会自动给出类型。
这里有一个例子。

  1. // No type annotations here, but TypeScript can spot the bug
  2. const names = ["Alice", "Bob", "Eve"];
  3. // Contextual typing for function
  4. names.forEach(function (s) {
  5. console.log(s.toUppercase());
  6. Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
  7. });
  8. // Contextual typing also applies to arrow functions
  9. names.forEach((s) => {
  10. console.log(s.toUppercase());
  11. Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
  12. });

尽管参数s没有类型注释,但TypeScript使用forEach函数的类型,以及数组的推断类型,来确定s的类型。
这个过程被称为上下文类型化,因为函数发生的上下文告知了它应该有什么类型。
与推理规则类似,你不需要明确地学习这种情况是如何发生的,但是理解它确实发生了,可以帮助你注意到什么时候不需要类型注释。稍后,我们将看到更多关于一个值发生的上下文如何影响其类型的例子。

函数表达式

如果要我们现在写一个对函数表达式(Function Expression)的定义,可能会写成这样:

let mySum = function (x: number, y: number): number { return x + y; };

这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 mySum 添加类型,则应该是这样:

let mySum: (x: number, y: number) => number = function (x: number, y: number): number { return x + y; };

注意不要混淆了 TypeScript 中的 => 和 ES6 中的 => (参考下面函数声明)

函数(未实现)声明

在没有提供函数实现的情况下,有两种声明函数类型的方式:

对象形式描述函数形状(type和interface都可以)

  1. type LongHand = {
  2. (a: number): number;
  3. };

也可以用接口定义函数的形状,与type作用一样

  1. interface SearchFunc {
  2. (source: string, subString: string): boolean;
  3. }
  4. let mySearch: SearchFunc;
  5. mySearch = function(source: string, subString: string) {
  6. return source.search(subString) !== -1;
  7. }

函数表达式形式定义函数类型

  1. type ShortHand = (a: number) => number;

在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>
image.png
image.png

使用区别

上面代码中的两个例子完全相同。但是,当你想使用函数重载时,只能用第一种方式

  1. type LongHandAllowsOverloadDeclarations = {
  2. (a: number): number;
  3. (a: string): string;
  4. };