这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战
函数是JavaScript应用程序的基础,是JavaScript的一等公民
在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义_行为_的地方。
TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。
基本属性
具名函数定义
/**
* 在TS中,使用function关键字来定义一个最基本的函数
* @param num1 求和的第一个值 类型为 number
* @param num2 求和的第二个值 类型为 number
* @returns 返回两数之和 类型为number --- 返回值的类型 一般可以不写 ts的类型推断会自动推测出来
*/
function add(num1: number, num2: number): number {
return num1 + num2
}
匿名函数定义
/**
*
* @param {number} num1
* @param {number} num2
* @returns {number}
*/
const add = (num1: number, num2: number) => num1 + num2
// 变量为函数类型
let add: (num1: number, num2: number) => number
add = (num1: number, num2: number): number => num1 + num2
如果一个函数中,使用了在函数外部定义的变量,那么该变量的类型是不会体现在这个函数中的
而当函数这么做时,我们说它‘捕获’了这些变量。实际上,这些捕获变量是函数的隐藏状态并不是组成API的一部分。
const num = 33
// 定义类型别名
type Add = (num1: number, num2: number) => number
// 这里的num是定义在函数add之外的变量
// 所以num的数据类型是不会体现在add函数的ts类型结构中的
const add: Add = (num1: number, num2: number) => num1 + num2 + num
完整定义
函数类型包含两部分:参数类型和返回值类型
(num1: number, num2: number) => number
函数参数
-
我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型。
-
这个名字只是为了增加可读性, 并不需要和形参名保持一致
-
TypeScript只要求对应位置上的参数的参数类型是匹配的,那么就认为它是有效的函数类型,而不在乎参数名是否正确
函数返回值
- 在函数和返回值类型之前使用(
=>)符号 来进行分割,=>右边即为函数的返回值 - 返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为
void而不能留空。
类型推测
// 写法1
const add: (num1: number, num2: number) => number =
function(num1, num2) { return num1 + num2; };
// 写法2
const add = function(num1: number, num2: number): number { return num1 + num2; };
可选参数
JavaScript里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined
在TypeScript里我们可以在参数名旁使用?实现可选参数的功能
// 和JS不一样的是
// 在JS中,可选参数可以出现在形参列表中的任意位置,如果不是最后一个,在实际传参的时候,使用undefined进行占位即可
// 在TS中,可选参数 必须 出现在必选参数后边
type Add = (num1: number, num2: number, num3?: number) => number
let add: Add
add = (num1: number, num2: number) => num1 + num2
add = (num1: number, num2: number, num3: number) => num1 + num2 + num3
默认参数
在TypeScript里,我们也可以为参数在用户没有传递这个参数或传递的值是undefined时提供一个默认值
// 默认参数的写法和js是一致的
// 默认参数是定义在函数实际定义中 --- 默认参数是不可以定义在接口或类型别名中的
// --- 在接口或类型别名中对应的是可选参数
let sum = (num1: number, num2: number = 2) => num1 + num2
// num2:number = 2 --- 已经为num2赋值了默认值2,ts会自动推测出num2的数据类型是number
// 所以num2的数据类型默认可以省略
sum = (num1: number, num2 = 2) => num1 + num2
let sum = (num1: number, num2: number = 2) => num1 + num2
// 和
sum = (num1: number, num2?: number) => num1 + num2
// 在TS中所对应的类型是一致的
// 都是 (num1: number, num2?: number) => number
// 也就是在函数类型中,默认参数的默认值不会显示,而只会显示它是一个可选参数
// 但与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面
// 如果带默认值的参数出现在必须参数前面,用户必须明确的传入undefined值来获得默认值
剩余参数
必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在JavaScript里,你可以使用arguments或剩余参数来访问所有传入的参数。
剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个
编译器创建参数数组,名字是你在省略号(...)后面给定的名字,你可以在函数体内使用这个数组。
function foo(...args: number[]) {
console.log(args.length)
}
函数重载
JavaScript本身是个动态语言。 JavaScript里函数根据传入不同的参数而返回不同类型的数据是很常见的。
// 函数重载定义部分
// 函数重载只能使用function关键字
// 不可以使用接口或类型别名来定义函数重载
function getArr(target: number): string[]
function getArr(target: string): string[]
// 函数具体实现部分
// 单单存在函数重载部分,ts是会报错的
// 函数重载必须存在一个具体的函数实现
// TS会自动根据函数的实现和函数重载的定义
// 去自动从上往下 去使用匹配到的第一个函数重载定义
// 所以如果存在多个可以匹配到的函数重载定义
// 需要将最为精确的哪一个函数重载定义放置到最上边
function getArr(target: number | string) {
if (typeof target === 'number') {
target = String(target)
}
return target.split('')
}
console.log(getArr('Klaus'))
console.log(getArr(23))
函数中的this
JavaScript里,this的值在函数被调用的时候才会指定。 这是个既强大又灵活的特点
但是,这也就导致TS在编译阶段对代码进行类型检测的时候,可能无法准确推测出this所对应的类型结构
interface IPerson {
name: string,
sayHello(): void
}
const person: IPerson = {
name: 'Klaus',
sayHello () {
console.log(this.name)
}
}
person.sayHello()
此时,编辑器并不知道sayHello是如何调用的,所以此时的this在经过TS的类型推测后,其类型为any
interface IPerson {
name: string,
sayHello(): void
}
const person: IPerson = {
name: 'Klaus',
// 我们可以在函数调用的时候传入一个参数this来告诉编辑器,我们会使用什么方式来调用对应的方法
// this参数是个假的参数,它总是出现在参数列表的最前面
// 如果我们不希望函数内部使用this的时候,可以显示设置this的值为void
sayHello (this: IPerson) {
console.log(this.name)
}
}
person.sayHello()