TypeScript 函数的类型


作者:Seiya

时间:2019年07月31日


函数

函数是 JavaScript 应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在 TypeScript 里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义行为的地方。 TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。




函数声明

在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression):

// 函数声明(Function Declaration)
function sum(x, y) {
	return x + y;
}

// 函数表达式(Function Expression)
let mySum = function (x, y) {
	return x + y;
};


函数类型

我们可以给每个参数添加类型之后再为函数本身添加返回值类型。 TypeScript能够根据返回语句自动推断出返回值类型,因此我们通常省略它。

function sum(x: number, y: number): number {
	return x + y;
}

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

注意:

一个函数有输入和输出,要在 TypeScript 中对其进行约束,输入多余的(或者少于要求的)参数,是不被允许的。



完整的函数类型

函数类型包含两部分:参数类型和返回值类型。当写出完整函数类型的时候,这两部分都是需要的。我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型。返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为void而不能留空。

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

注意:

不要混淆了 TypeScript 中的 => 和 ES6 中的 =>

在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。



用接口定义函数的形状

interface SearchFunc {
	(source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
	return source.search(subString) !== -1;
}


可选参数

JavaScript 里,每个参数都是可选的,可传可不传。没传参的时候,它的值就是 undefined。在 TypeScript 里我们可以在参数名旁使用 ? 实现可选参数的功能。

function buildName(firstName: string, lastName?: string) {
	if (lastName) {
		return firstName + ' ' + lastName;
	} else {
		return firstName;
	}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

注意:

需要注意的是,可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必须参数了。



默认参数

在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数。此时就不受「可选参数必须接在必需参数后面」的限制了:

function buildName(firstName: string = 'Tom', lastName: string) {
	return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let cat = buildName(undefined, 'Cat');


剩余参数

必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。在 JavaScript 里,你可以使用 arguments 来访问所有传入的参数。在TypeScript里,你可以把所有参数收集到一个变量里。

剩余参数会被当做个数不限的可选参数。可以一个都没有,同样也可以有任意个。编译器创建参数数组,名字是你在省略号(...)后面给定的名字,你可以在函数体内使用这个数组:

function push(array: any[], ...items: any[]) {
	items.forEach(function(item) {
		array.push(item);
	});
}

let a = [];
push(a, 1, 2, 3);


重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。JavaScript 本身是个动态语言。 JavaScript里函数根据传入不同的参数而返回不同类型的数据是很常见的。


利用联合类型,我们可以这么实现:

function reverse(x: number | string): number | string {
	if (typeof x === 'number') {
		return Number(x.toString().split('').reverse().join(''));
	} else if (typeof x === 'string') {
		return x.split('').reverse().join('');
	}
}

然而这样有一个缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。


这时,我们可以使用重载定义多个 reverse 的函数类型:

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
	if (typeof x === 'number') {
		return Number(x.toString().split('').reverse().join(''));
	} else if (typeof x === 'string') {
		return x.split('').reverse().join('');
	}
}

上例中,我们重复定义了多次函数 reverse,前几次都是函数定义,最后一次是函数实现。在编辑器的代码提示中,可以正确的看到前两个提示。

注意:

TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。

最后更新时间: 2019-7-31 18:23:33