TypeScript 初识 - 函数
函数是 JavaScript 的第一等公民,函数在 JavaScript 中可以实现抽象层、模拟类、信息隐藏和模块等等。TypeScript 在一定基础上扩展了函数的功能。
函数类型
函数返回值类型
我们可以给每个参数添加类型之后再为函数本身添加返回值类型。TypeScript 能够根据返回语句自动推断出返回值类型,所以通常可以省略它:
function add(x: number, y: number): number { return x + y; } // 匿名函数 let myAdd = function(x: number, y: number): number { return x + y; };
完整函数类型
完整的函数类型包含两部分:参数类型和返回值类型。
// (x: number, y: number) => number 为函数的类型 // 其中的 x、y 只是为了增加可读性,只要参数类型是匹配的,无需匹配参数名是否一样 // 参数类型和返回值类型之间使用 => 符号 let myAdd: (x: number, y: number) => number = function( x: number, y: number ): number { return x + y; };
返回值类型是函数类型的必要部分,函数没有返回值的情况,也必须要指定返回值为 void
。
推断类型
函数定义的时候,如果赋值语句只有一边指定了语句,TypeScript 编译器会自动识别出类型:
// myAdd has the full function type let myAdd = function(x: number, y: number): number { return x + y; }; // The parameters `x` and `y` have the type number let myAdd: (baseValue: number, increment: number) => number = function(x, y) { return x + y; };
这叫做“按上下文归类”,是类型推论的一种。
可选参数和默认参数
默认情况下,TypeScript 会判断传入函数的参数和函数定义的参数是否一致,个数、类型都会进行判断。
let myAdd: (baseValue: number, increment: number) => number = function(x, y) { return x + y; }; // An argument for 'increment' was not provided. myAdd(1); myAdd(1, 2); // 应有 2 个参数,但获得 3 个。 myAdd(1, 2, 3);
在 TypeScript 中,可以加上 ?
实现可选参数的功能,可选参数必须放在必需参数的前面:
function buildName(firstName: string, lastName?: string) { if (lastName) { return firstName + ' ' + lastName; } else { return firstName; } } // Bob let result1 = buildName('Bob'); // 应有 1-2 个参数,但获得 3 个。 let result2 = buildName('Bob', 'Adams', 'Sr.'); // Bob Adams let result3 = buildName('Bob', 'Adams');
在定义函数的时候,可以给形参进行赋值作为默认值,仅当不传值或传入的值为 undefined
时,函数会使用这个默认值:
function buildName(firstName: string, lastName = 'Smith') { return firstName + ' ' + lastName; } // Bob Smith let result1 = buildName('Bob'); // Bob Smith let result2 = buildName('Bob', undefined);
函数的默认值不需要放到必需参数的后面,但是,放在必需参数前面的默认值,只有显式地传递 undefined
时会生效。
剩余参数
在 JavaScript 中,可以使用 arguments
访问传入的所有参数;在 TypeScript 中同样可以使用。
剩余参数将不定数量的参数当作一个数组,表示 0 或多个参数:
// ... 后面加上一个数组,这就是剩余参数 function buildName(firstName: string, ...restOfName: string[]) { return firstName + ' ' + restOfName.join(' '); } // Bob console.log(buildName('Bob')); // Bob Smith Steven console.log(buildName('Bob', 'Smith', 'Steven'));
言下之意,剩余参数必须是最后的参数,不能够放到其他参数的前面。
重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。在 JavaScript 中,一般是判断传入参数的个数或类型等等情况实现重载。
以 TypeScript 中联合类型的特性,实现 JavaScript 版本的重载:
function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number( x .toString() .split('') .reverse() .join('') ); } return x .split('') .reverse() .join(''); } // function reverse(x: string | number): string | number console.log(reverse(123)); console.log(reverse('123'));
上面是是实现重载的一个方法,但是这样实现重载更难懂,不能精确表达。TypeScript 提供更能精确表达的重载方法:
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('') ); } return x .split('') .reverse() .join(''); } // function reverse(x: number): number (+1 overload) console.log(reverse(123)); // function reverse(x: string): string (+1 overload) console.log(reverse('123'));
注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。