likes
comments
collection
share

TypeScript入门之函数

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

简介

JavaScript 中,函数是构建应用的一块基石,我们可以使用函数抽离可复用的逻辑、抽象模型、封装过程。在TypeScript中,函数仍然是最基本、最重要的概念之一。下面就来看看TypeScript中的函数都有哪些特性。

函数定义

直接定义

直接定义这种方式是最好理解的。

function fun_1(num1: number, num2: number): number {
  return num1 + num2;
}

const fun_2 = (num1: number, str1: string): string => {
  return num1 + str1;
};

function fun_3(): void {
  console.log("fun_3");
}

通过表达式定义

const fun_4: (num1: number, str1: string) => string = (num1: number, str1: string) => {
  return num1 + str1;
};

通过类型别名定义

我们还可以把函数表达式定义成类型别名。

type fun5Type = (num1: number, str1: string) => string

const fun_5: fun5Type = (num1: number, str1: string) => {
  return num1 + str1;
};

函数参数

函数参数这块在JS中都有与之对应的特性,基本上差不多。

可选参数

type Add = (x: number, y: number, z?: number) => number;

let add: Add = (arg1, arg2, arg3) => arg1 + arg2 + arg3;

add(1, 2); // success   3
add(1, 2, 3); // success   6

JavaScript中,上面代码中后面两个函数调用都不会报错, 只不过add(1, 2, 3)可以返回正确结果3add(1)会返回NaN。而在TypeScript中我们设置了指定的参数,那么在使用该类型时,传入的参数必须与定义的参数类型和数量一致。

但有时候,函数有些参数不是必须的,我们就可以将函数的参数设置为可选参数。可选参数只需在参数名后跟随一个?即可,这就是可选参数。

需要注意,可选参数必须放在必选参数后面,这和在 JS 中定义函数是一致的。来看例子:

type Add2 = (x?: number, y: number) => number;  // error 必选参数不能位于可选参

// 需要改成
type Add2 = (y: number, x?: number) => number;

默认参数

当为参数指定了默认参数时,TypeScript 会识别默认参数的类型;当调用函数时,如果给这个带默认值的参数传了别的类型的参数则会报错:

const add = (x: number, y = 2) => {
  return x + y;
};
add(1, "ts"); // error 类型"string"的参数不能赋给类型"number"的参数

当然也可以显式地给默认参数 y 设置类型:

const add = (x: number, y: number = 2) => {
  return x + y;
};

默认参数不比可选参数,默认参数可以放在参数列表的任意位置。

const add = (x: number = 2, y: number) => {
  return x + y;
};

当默认参数不在参数列表的第一个的时候我们该怎么使用呢?

// 使用undefined占位就可以啦
add(undefined, 10) // 12

剩余参数

剩余参数与JavaScript中的语法类似,需要用 ... 来表示剩余参数。

const add = (a: number, ...rest: number[]) => rest.reduce(((a, b) => a + b), a)

上面的例子参数 rest 则是一个由number组成的数组,在本函数中用 reduce 进行了累加求和。

函数重载

学过java的通过肯定知道函数的重载和重写。

那么在 TypeScript 中函数重载是怎么定义的呢?

其实跟java也是类似的,就是相同的方法名,只是方法参数列表不一样。和java的区别就是 TypeScript 只能是最后有一个方法来完整实现,而不是每个方法都有对应的实现。

interface Direction {
  top: number;
  bottom?: number;
  left?: number;
  right?: number;
}

// 参数列表可能的情况 1个参数 2个参数 4个参数,只需定义,不需要实现
function assigned(all: number): Direction;
function assigned(topAndBottom: number, leftAndRight: number): Direction;
function assigned(
  top: number,
  right: number,
  bottom: number,
  left: number
): Direction;

// 方法完整的实现
function assigned(a: number, b?: number, c?: number, d?: number) {
  if (b === undefined && c === undefined && d === undefined) {
    b = c = d = a;
  } else if (c === undefined && d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d,
  };
}

assigned(1);
assigned(1, 2);
assigned(1, 2, 3); // 没有定义三个参数的函数,编译阶段直接报错
assigned(1, 2, 3, 4);

最后我们分别传入不同数量的参数,发现只有在三个参数的情况下报错了。因为我们没有定义三个参数的方法。

TypeScript入门之函数

相较于JS,函数重载可以让我们在编写代码阶段就能及时发现错误。很大的提升了我们的开发效率。

is关键字

is关键字一般和函数搭配使用。

我们来看个例子

function isString(test: any): boolean {
  return typeof test === 'string';
}

function example(foo: number | string){
  if(isString(foo)){
    console.log(foo.length); // string function
  }
}

example('hello world');

我们看到由于foo: number | stringstringnumber的联合类型,后面又直接使用了.length属性,所以会报错。

TypeScript入门之函数

那有什么办法可以解决呢?

function example(foo: number | string) {
  if (isString(foo) && typeof foo === "string") {
    console.log(foo.length); // string类型才有length属性
  }
}

第二种就是使用我们的is关键字。

function isString(test: any): test is string {
  return typeof test === 'string';
}

function example(foo: number | string){
  if(isString(foo)){
    console.log(foo.length); // string function
  }
}

example('hello world');

我们在isString方法后面不再返回boolean类型而是test is string。这句话什么意思呢?

意思就是如果isString方法返回true,就表示参数teststring类型的。所以后面直接调用.length属性就不会报错。

系列文章

后记

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!

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