likes
comments
collection
share

TypeScript 学习笔记(六):函数类型

作者站长头像
站长
· 阅读数 5

前言

介绍

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

TS中,函数的定义和JS一样,不过是添加了类型的约束。以下是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,如以下例子。

type MyFunc = (string, number) => number;
// (string: any, number: any) => number

只要参数类型是匹配的,那么就认为它是有效的函数类型,而不在乎参数名是否正确。 意思就是函数类型里面的参数名与实际参数名,可以不一致。

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

Function类型

TS提供Function类型表示函数,任何函数都属于这个类型。

function doSomething(f:Function) {
  return f(1, 2, 3);
}

Function 类型的函数可以接受任意数量的参数,每个参数的类型都是any,返回值的类型也是any,代表没有任何约束。

函数的参数

TS里的每个函数参数都是必须的。这不是指不能传递 nullundefined作为参数,而是说编译器检查用户是否为每个参数都传入了值。 编译器还会假设只有这些参数会被传递进函数。 简单地说,传递给一个函数的参数个数必须与函数的参数个数一致。

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里,我们可以使用?实现可选参数的功能。

function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}

参数名带有问号,表示该参数的类型实际上是原始类型|undefined,它有可能为undefined

比如,下面例子的x虽然类型声明为number,但是实际上是number|undefined。等同于说x可以赋值为undefined

function f(x?:number) {
  return x;
}

f(undefined) // 正确

但是,反过来就不成立,类型显式设为undefined的参数,就不能省略。

function f(x:number|undefined) {
  return x;
}

f() // 报错

上面示例中,参数x的类型是number|undefined,表示要么传入一个数值,要么传入undefined,如果省略这个参数,就会报错。

可选参数必须跟在必须参数后面。 通俗的讲,就是有?的必须在没有?的参数后面。

let myFunc:
  (a?:number, b:number) => number; // 报错

上面示例中,可选参数在必选参数前面,就报错了。

默认参数

TS的默认参数写法,与JS一样。

设置了默认值的参数,就是可选的。如果不传入该参数,它就会等于默认值。

function createPoint(
  x:number = 0,
  y:number = 0
):[number, number] {
  return [x, y];
}

createPoint() // [0, 0]

所以可选参数与默认值不能同时使用。 下面例子中,x是可选参数,还设置了默认值,结果就报错了。

// 报错
function f(x?: number = 0) {
  // ...
}

rest参数

rest参数表示函数剩余的所有参数,它可以是数组(剩余参数类型相同),也可能是元组(剩余参数类型不同)。

// rest 参数为数组
function joinNumbers(...nums:number[]) {
  // ...
}

// rest 参数为元组
function f(...args:[boolean, number]) {
  // ...
}

下面是一个rest参数的例子。

function multiply(n:number, ...m:number[]) {
  return m.map((x) => n * x);
}

rest 参数可以嵌套。

function f(...args:[boolean, ...string[]]) {
  // ...
}

rest 参数可以与变量解构结合使用。

function repeat(
  ...[str, times]: [string, number]
):string {
  return str.repeat(times);
}

// 等同于
function repeat(
  str: string,
  times: number
):string {
  return str.repeat(times);
}

readonly只读参数

如果函数内部不能修改某个参数,可以在函数定义时,在参数类型前面加上readonly关键字,表示这是只读参数。

function arraySum(
  arr:readonly number[]
) {
  // ...
  arr[0] = 0; // 报错
}

上面示例中,参数arr的类型是readonly number[],表示为只读参数。如果函数体内部修改这个数组,就会报错。 但是,readonly关键字目前只允许用在数组和元组类型的参数前面,如果用在其他类型的参数前面,就会报错。

转载自:https://juejin.cn/post/7358375367341277235
评论
请登录