Skip to content

TypeScript - 函数

函数(Functions)是创建可读、可维护和可重用代码的基本构建块。它们封装了一组旨在执行特定任务的语句。将代码组织到函数中使程序更具逻辑性且易于管理。

在 TypeScript 中,就像 JavaScript 一样,函数是第一类公民(first-class citizens)。它们可以被定义、作为参数传递、从其他函数返回以及赋值给变量。

TypeScript 通过为参数和返回值添加显式的类型注解 (type annotations) 来增强 JavaScript 函数,提供编译时安全 (compile-time safety)。

概念 (Concept)描述 (Description)
定义函数 (Defining a Function)指定函数的名称、参数(带类型)、返回值类型,以及要执行的代码块(函数体)。
调用函数 (Calling a Function)通过函数的名称后跟括号 () 来调用函数,并传递任何必需的参数 (arguments)。
返回值 (Return Values)函数可以使用 return 关键字返回一个值。返回值的类型应与函数声明的返回值类型匹配。不返回值的函数其返回值类型为 void。
参数 (Parameters) 与 实参 (Arguments)参数是在函数定义中列出的变量。实参是在调用函数时传递给函数的实际值。

TypeScript 支持几种定义函数的方式:

1. 命名函数声明 (Named Function Declaration)

Section titled “1. 命名函数声明 (Named Function Declaration)”
function greet(name: string): string {
return `Hello, ${name}!`;
}
function logMessage(message: string): void {
console.log(message);
}
let greeting = greet("Alice"); // greeting 的类型被推断为 string
logMessage(greeting);

2. 函数表达式 (匿名函数) (Function Expression (Anonymous Function))

Section titled “2. 函数表达式 (匿名函数) (Function Expression (Anonymous Function))”

将函数赋值给一个变量。函数本身可以是匿名的。

const add = function(x: number, y: number): number {
return x + y;
};
let sum: number = add(10, 5);

3. 箭头函数表达式 (Arrow Function Expression)

Section titled “3. 箭头函数表达式 (Arrow Function Expression)”

函数表达式的简洁语法,特别适用于内联函数和回调函数。箭头函数捕获封闭上下文(词法作用域 this)的 this 值。

const multiply = (x: number, y: number): number => {
return x * y;
};
// 简洁函数体(单个表达式,隐式返回)
const subtract = (x: number, y: number): number => x - y;
// 没有参数的箭头函数
const logTime = (): void => { console.log(new Date()); };
// 有一个参数的箭头函数(括号可选)
const square = (x: number): number => x * x;
// const square = x => x * x; // 如果可能,类型会被推断,但显式类型通常更好
let product: number = multiply(4, 6);
logTime();

参数可以通过在其名称后添加 ? 来标记为可选。可选参数必须出现在必需参数之后。如果未提供可选参数,其值为 undefined。

function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName} ${lastName}`;
}
else {
return firstName;
}
}
let name1 = buildName("Bob"); // 输出: Bob
let name2 = buildName("Bob", "Adams"); // 输出: Bob Adams
console.log(name1);
console.log(name2);

你可以为参数提供默认值。如果未为默认参数提供实参(或传递了 undefined),则使用默认值。默认参数不一定需要出现在必需参数之后,但这样做通常能提高可读性。

function calculateRate(price: number, rate: number = 0.05): number {
return price * rate;
}
let amount1 = calculateRate(1000); // 使用默认比率 0.05 -> 50
let amount2 = calculateRate(1000, 0.1); // 使用提供的比率 0.1 -> 100
console.log(amount1);
console.log(amount2);

注意:参数不能同时是可选参数 (?) 并拥有默认值。

使用剩余语法 (...) 将多个实参收集到一个数组参数中。剩余参数必须是函数定义中的最后一个参数,并且必须是数组类型。

function sumAll(...numbers: number[]): number {
let total = 0;
for (const num of numbers) {
total += num;
}
return total;
}
let total1 = sumAll(1, 2, 3); // 输出: 6
let total2 = sumAll(10, 20, 30, 40); // 输出: 100
console.log(total1);
console.log(total2);

函数重载允许为一个函数名定义多个函数签名(参数类型和返回值类型),后跟一个实现函数体。该实现函数体的签名必须与所有重载签名兼容。TypeScript 使用重载签名来对函数调用进行类型检查。

// 重载签名
function process(value: string): string;
function process(value: number): number;
function process(value: boolean): boolean;
// 实现签名(必须与重载兼容)
function process(value: string | number | boolean): string | number | boolean {
if (typeof value === 'string') {
return value.toUpperCase();
}
if (typeof value === 'number') {
return value * 2;
}
return !value;
}
let result1: string = process("data"); // 正确推断为 string 类型
let result2: number = process(10); // 正确推断为 number 类型
let result3: boolean = process(true); // 正确推断为 boolean 类型
console.log(result1); // 输出: DATA
console.log(result2); // 输出: 20
console.log(result3); // 输出: false
// let errorResult = process({ a: 1 }); // 错误: 没有重载匹配此调用。

重载对于函数基于传递的实参类型或数量表现不同行为时非常有用。

其他函数概念 (Other Function Concepts)

Section titled “其他函数概念 (Other Function Concepts)”
  • **this 关键字:**行为取决于函数如何被调用。箭头函数拥有词法作用域的 this,而标准函数通常依赖于调用 site(例如,对象方法、独立调用)。TypeScript 提供了一些方式来显式地为 this 添加类型。
  • **递归 (Recursion):**函数调用自身。需要一个基本情况 (base case) 来防止无限循环。
  • **高阶函数 (Higher-Order Functions):**接受其他函数作为实参或返回函数的函数。
  • **泛型 (Generics):**创建可重用函数,这些函数可以处理各种类型同时保持类型安全(在更高级主题中介绍)。
  • 始终为参数和返回值提供显式的类型注解,除非类型推断 (type inference) 显而易见且微不足道。
  • 由于简洁的语法和词法作用域的 this,优先为回调函数和简短简单的函数使用箭头函数。
  • 除非你明确需要重新赋值该变量,否则为函数表达式使用 const。
  • 让函数专注于单一任务(单一职责原则 Single Responsibility Principle)。
  • 当函数确实根据类型处理不同的参数模式时,使用函数重载,但避免过于复杂的重载集合。