函数

本篇笔记我们介绍TypeScript中函数的定义、可选参数、默认参数、剩余参数、函数重载等相关内容。

函数的基本类型标注

TypeScript中,我们可以为函数的参数和返回值添加类型标注。下面是一个例子。

function add(a: number, b: number): number {
  return a + b;
}

const result = add(1, 2); // result的类型为number

代码中,我们定义了一个add函数,它接收两个number类型的参数,并返回number类型的结果。TypeScript会在编译时检查参数和返回值的类型是否匹配,如果类型不匹配则会报错。

对于箭头函数,类型标注的方式类似。

const multiply = (a: number, b: number): number => {
  return a * b;
};

当函数没有返回值时,我们使用void类型。

function logMessage(message: string): void {
  console.log(message);
}

函数类型表达式

除了在函数定义时标注类型,我们还可以使用函数类型表达式来描述函数的类型,这在将函数作为参数传递或定义回调函数类型时非常有用。

type AddFn = (a: number, b: number) => number;

const add: AddFn = (a, b) => {
  return a + b;
};

代码中,我们使用type关键字定义了一个函数类型AddFn,它描述了接收两个number参数并返回number的函数。随后我们用这个类型来标注add变量,此时函数实现中的参数类型也可以省略,TypeScript会自动推断。

函数类型表达式可以直接在参数中使用,下面是一个例子。

function executeOperation(a: number, b: number, operation: (x: number, y: number) => number): number {
  return operation(a, b);
}

const result = executeOperation(10, 5, (x, y) => x - y);

可选参数和默认参数

TypeScript支持可选参数,使用?标记,注意可选参数必须放在必选参数之后。

function greet(name: string, greeting?: string): string {
  if (greeting) {
    return `${greeting}, ${name}!`;
  }
  return `Hello, ${name}!`;
}

greet("Tom");           // "Hello, Tom!"
greet("Tom", "Hi");     // "Hi, Tom!"

代码中,greeting是可选参数,调用时可以不传递该参数。需要注意的是,可选参数的类型实际上是string | undefined的联合类型。

默认参数则是在参数后使用=赋予默认值。

function greet(name: string, greeting: string = "Hello"): string {
  return `${greeting}, ${name}!`;
}

greet("Tom");           // "Hello, Tom!"
greet("Tom", "Hi");     // "Hi, Tom!"

与可选参数不同,默认参数的类型不可能包含undefined,因为当传入undefined时会使用默认值。

剩余参数(不定数量参数)

当函数需要接收不定数量的参数时,可以使用剩余参数(Rest Parameters)。剩余参数使用...语法,其类型本质是一个数组。

function sum(...numbers: number[]): number {
  return numbers.reduce((acc, cur) => acc + cur, 0);
}

sum(1, 2);          // 3
sum(1, 2, 3, 4, 5); // 15

注意剩余参数必须是函数中的最后一个参数。

函数重载

JavaScript本身不支持函数重载,但TypeScript提供了函数重载的类型声明能力。函数重载允许我们为同一个函数定义多个类型签名,以处理不同的参数类型组合。

function parseValue(value: string): string[];
function parseValue(value: number): number;
function parseValue(value: string | number): string[] | number {
  if (typeof value === "string") {
    return value.split("");
  }
  return value * 2;
}

const strResult = parseValue("hello"); // 类型为string[]
const numResult = parseValue(10);      // 类型为number

代码中,前两行是重载签名,它们声明了函数可以接受的不同参数类型及对应的返回类型。最后一个是实现签名,它必须兼容所有的重载签名。调用函数时,TypeScript会根据传入的参数类型选择匹配的重载签名,从而获得正确的返回类型。

注意:实现签名对外部调用者是不可见的,调用时只能使用重载签名中定义的参数类型。

this类型

在TypeScript中,我们可以显式声明函数中this的类型,this参数是一个特殊的伪参数,它必须放在参数列表的第一位。

interface User {
  name: string;
  greet(this: User): void;
}

const user: User = {
  name: "Tom",
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  },
};

user.greet(); // "Hello, I'm Tom"

代码中,我们在greet方法中声明了this的类型为User,这样在方法内部访问this时就能获得正确的类型提示,同时TypeScript也会检查方法的调用方式是否正确。不过这个this参数仅用于类型检查,不会出现在实际运行时的参数列表中,也就是说,调用user.greet()时仍然不需要传任何参数。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。