前言
在上一篇文章TypeScript 学习笔记(五):interface接口中我们学习了TS
中interface
接口,本篇文章我们主要了解TS
中的函数。
介绍
函数是JavaScript应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义行为的地方。 TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。
在TS
中,函数的定义和JS
一样,不过是添加了类型的约束。以下是TS
中函数的两种写法案例。
TS
// 写法一
const hello = function (txt:string) {
console.log('hello ' + txt);
}
// 写法二
const hello:
(txt:string) => void
= function (txt) {
console.log('hello ' + txt);
};
- 写法一是通过等号右边的函数类型,推断出变量
hello
的类型。 - 写法二则是使用箭头函数的形式,为变量
hello
指定类型,参数的类型写在箭头左侧,返回值的类型写在箭头右侧。
写法二有两个地方需要注意:
第一,函数的参数要放在圆括号里面,不放会报错。 第二,类型里面的参数名是必须的。如果写成(string) => void
,TypeScript 会理解成函数有一个名叫 string 的参数,并且这个string
参数的类型是any
,如以下例子。
TS
type MyFunc = (string, number) => number;
// (string: any, number: any) => number
只要参数类型是匹配的,那么就认为它是有效的函数类型,而不在乎参数名是否正确。 意思就是函数类型里面的参数名与实际参数名,可以不一致。
TS
let myAdd: (baseValue: number, increment: number) => number =
function(x: number, y: number): number { return x + y; };
Function
类型
TS
提供Function
类型表示函数,任何函数都属于这个类型。
TS
function doSomething(f:Function) {
return f(1, 2, 3);
}
Function 类型的函数可以接受任意数量的参数,每个参数的类型都是any
,返回值的类型也是any
,代表没有任何约束。
函数的参数
TS
里的每个函数参数都是必须的。这不是指不能传递 null
或undefined
作为参数,而是说编译器检查用户是否为每个参数都传入了值。 编译器还会假设只有这些参数会被传递进函数。 简单地说,传递给一个函数的参数个数必须与函数的参数个数一致。
TS
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // 报错,少了
let result2 = buildName("Bob", "Adams", "Sr."); // 报错,多了
let result3 = buildName("Bob", "Adams"); // 正确
可选参数
在JS
中,每个参数都是可传可不传。没传参的时候,默认值是undefined
。 这一点在TS
里,我们可以使用?
实现可选参数的功能。
TS
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
参数名带有问号,表示该参数的类型实际上是原始类型|undefined
,它有可能为undefined
。
比如,下面例子的x
虽然类型声明为number
,但是实际上是number|undefined
。等同于说x
可以赋值为undefined
。
TS
function f(x?:number) {
return x;
}
f(undefined) // 正确
但是,反过来就不成立,类型显式设为undefined
的参数,就不能省略。
javascript
function f(x:number|undefined) {
return x;
}
f() // 报错
上面示例中,参数x
的类型是number|undefined
,表示要么传入一个数值,要么传入undefined
,如果省略这个参数,就会报错。
可选参数必须跟在必须参数后面。 通俗的讲,就是有?
的必须在没有?
的参数后面。
TS
let myFunc:
(a?:number, b:number) => number; // 报错
上面示例中,可选参数在必选参数前面,就报错了。
默认参数
TS
的默认参数写法,与JS
一样。
设置了默认值的参数,就是可选的。如果不传入该参数,它就会等于默认值。
TS
function createPoint(
x:number = 0,
y:number = 0
):[number, number] {
return [x, y];
}
createPoint() // [0, 0]
所以可选参数与默认值不能同时使用。 下面例子中,x
是可选参数,还设置了默认值,结果就报错了。
TS
// 报错
function f(x?: number = 0) {
// ...
}
rest
参数
rest
参数表示函数剩余的所有参数,它可以是数组(剩余参数类型相同),也可能是元组(剩余参数类型不同)。
TS
// rest 参数为数组
function joinNumbers(...nums:number[]) {
// ...
}
// rest 参数为元组
function f(...args:[boolean, number]) {
// ...
}
下面是一个rest
参数的例子。
TS
function multiply(n:number, ...m:number[]) {
return m.map((x) => n * x);
}
rest 参数可以嵌套。
TS
function f(...args:[boolean, ...string[]]) {
// ...
}
rest 参数可以与变量解构结合使用。
TS
function repeat(
...[str, times]: [string, number]
):string {
return str.repeat(times);
}
// 等同于
function repeat(
str: string,
times: number
):string {
return str.repeat(times);
}
readonly
只读参数
如果函数内部不能修改某个参数,可以在函数定义时,在参数类型前面加上readonly
关键字,表示这是只读参数。
TS
function arraySum(
arr:readonly number[]
) {
// ...
arr[0] = 0; // 报错
}
上面示例中,参数arr
的类型是readonly number[]
,表示为只读参数。如果函数体内部修改这个数组,就会报错。 但是,readonly
关键字目前只允许用在数组和元组类型的参数前面,如果用在其他类型的参数前面,就会报错。