Skip to content

函数类型

概述

函数类型(Function Types)是 TypeScript 类型系统的重要组成部分,用于描述函数的参数类型和返回值类型。通过函数类型,我们可以在编译时检查函数调用是否正确,确保传入的参数类型匹配,返回值类型符合预期。TypeScript 支持多种函数类型定义方式,包括函数声明、函数表达式、箭头函数等,并提供了可选参数、默认参数、剩余参数等灵活的特性。

基本语法

函数声明类型

函数声明可以直接在参数和返回值上添加类型注解:

typescript
// 基本函数类型声明
function greet(name: string): string {
  return `Hello, ${name}!`;
}

// 无返回值的函数
function logMessage(message: string): void {
  console.log(message);
}

// 返回数字的函数
function add(a: number, b: number): number {
  return a + b;
}

函数表达式类型

函数表达式可以使用类型注解来指定函数类型:

typescript
// 函数表达式类型
const greet: (name: string) => string = function(name: string): string {
  return `Hello, ${name}!`;
};

// 使用箭头函数
const add: (a: number, b: number) => number = (a: number, b: number): number => {
  return a + b;
};

函数类型别名

使用类型别名可以定义可复用的函数类型:

typescript
// 定义函数类型别名
type GreetFunction = (name: string) => string;
type MathOperation = (a: number, b: number) => number;

// 使用函数类型别名
const greet: GreetFunction = (name: string): string => {
  return `Hello, ${name}!`;
};

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

函数参数类型

必需参数

函数参数默认是必需的,调用时必须提供所有参数:

typescript
// 必需参数
function createUser(name: string, age: number, email: string): void {
  console.log(`User: ${name}, Age: ${age}, Email: ${email}`);
}

// ✅ 正确:提供所有参数
createUser("Alice", 25, "alice@example.com");

// ❌ 错误:缺少参数
createUser("Bob", 30); // Error: Expected 3 arguments, but got 2

可选参数

使用 ? 标记参数为可选,可选参数必须放在必需参数之后:

typescript
// 可选参数
function createUser(
  name: string,
  age: number,
  email?: string  // 可选参数
): void {
  console.log(`User: ${name}, Age: ${age}`);
  if (email) {
    console.log(`Email: ${email}`);
  }
}

// ✅ 正确:提供所有参数
createUser("Alice", 25, "alice@example.com");

// ✅ 正确:省略可选参数
createUser("Bob", 30);

// ❌ 错误:可选参数必须在必需参数之后
function badFunction(optional?: string, required: string) {
  // Error: A required parameter cannot follow an optional parameter
}

提示

可选参数在函数内部可能是 undefined,使用前应该进行检查。

默认参数

使用默认值可以为参数提供默认值,有默认值的参数也是可选的:

typescript
// 默认参数
function greet(name: string, greeting: string = "Hello"): string {
  return `${greeting}, ${name}!`;
}

// ✅ 使用默认值
console.log(greet("Alice")); // "Hello, Alice!"

// ✅ 提供自定义值
console.log(greet("Bob", "Hi")); // "Hi, Bob!"

// 默认参数也可以使用表达式
function createId(prefix: string = "user", timestamp: number = Date.now()): string {
  return `${prefix}-${timestamp}`;
}

信息

有默认值的参数在类型上等同于可选参数,但不需要使用 ? 标记。

剩余参数

使用剩余参数(Rest Parameters)可以接收任意数量的参数:

typescript
// 剩余参数:使用 ... 语法
function sum(...numbers: number[]): number {
  return numbers.reduce((total, num) => total + num, 0);
}

// ✅ 可以传入任意数量的参数
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
console.log(sum()); // 0

// 剩余参数必须放在最后
function processData(
  name: string,
  ...values: number[]  // 剩余参数必须在最后
): void {
  console.log(`Name: ${name}, Values: ${values.join(", ")}`);
}

processData("test", 1, 2, 3); // "Name: test, Values: 1, 2, 3"

箭头函数类型

箭头函数(Arrow Functions)是 ES6 引入的语法,TypeScript 完全支持箭头函数的类型注解:

typescript
// 箭头函数类型注解
const add = (a: number, b: number): number => {
  return a + b;
};

// 简写形式(单表达式)
const multiply = (a: number, b: number): number => a * b;

// 无参数箭头函数
const getCurrentTime = (): Date => new Date();

// 单参数箭头函数可以省略括号
const double = (x: number): number => x * 2;

// 箭头函数作为参数
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((n: number): number => n * 2);

箭头函数类型定义

可以使用类型别名定义箭头函数的类型:

typescript
// 定义箭头函数类型
type NumberOperation = (a: number, b: number) => number;
type StringTransformer = (str: string) => string;

// 使用类型别名
const add: NumberOperation = (a, b) => a + b;
const subtract: NumberOperation = (a, b) => a - b;

const toUpperCase: StringTransformer = (str) => str.toUpperCase();
const toLowerCase: StringTransformer = (str) => str.toLowerCase();

函数返回类型

显式返回类型

显式指定返回类型可以让代码更清晰,也便于类型检查:

typescript
// 显式返回类型
function calculate(a: number, b: number): number {
  return a + b;
}

// 返回对象类型
function createUser(name: string, age: number): { name: string; age: number } {
  return { name, age };
}

// 返回数组类型
function getNumbers(): number[] {
  return [1, 2, 3, 4, 5];
}

void 返回类型

void 表示函数不返回任何值:

typescript
// void 返回类型
function logMessage(message: string): void {
  console.log(message);
  // 没有 return 语句,或 return; 不返回值
}

// void 函数不能返回值
function badFunction(): void {
  return "something"; // Error: Type 'string' is not assignable to type 'void'
}

never 返回类型

never 表示函数永远不会正常返回(抛出异常或无限循环):

typescript
// never 返回类型
function throwError(message: string): never {
  throw new Error(message);
  // 函数永远不会正常返回
}

function infiniteLoop(): never {
  while (true) {
    // 无限循环,永远不会返回
  }
}

类型推断

TypeScript 可以自动推断函数的返回类型:

typescript
// TypeScript 自动推断返回类型为 number
function add(a: number, b: number) {
  return a + b; // 推断为 number
}

// 推断为 string
function greet(name: string) {
  return `Hello, ${name}!`; // 推断为 string
}

// 推断为 { name: string; age: number }
function createUser(name: string, age: number) {
  return { name, age }; // 推断为对象类型
}

提示

虽然 TypeScript 可以推断返回类型,但显式声明返回类型可以让代码更清晰,也便于发现类型错误。

使用示例

示例 1:用户管理函数

typescript
// 定义用户类型
type User = {
  id: number;
  name: string;
  email: string;
  age?: number;
};

// 创建用户函数
function createUser(
  name: string,
  email: string,
  age?: number
): User {
  const id = Date.now(); // 简单的 ID 生成
  return {
    id,
    name,
    email,
    age
  };
}

// 更新用户函数
function updateUser(
  user: User,
  updates: Partial<User>
): User {
  return { ...user, ...updates };
}

// 删除用户函数
function deleteUser(userId: number): boolean {
  // 模拟删除操作
  console.log(`Deleting user ${userId}`);
  return true;
}

// 使用示例
const user = createUser("Alice", "alice@example.com", 25);
console.log(user); // { id: ..., name: "Alice", email: "alice@example.com", age: 25 }

const updatedUser = updateUser(user, { age: 26 });
console.log(updatedUser); // { id: ..., name: "Alice", email: "alice@example.com", age: 26 }

示例 2:数学运算函数

typescript
// 定义数学运算函数类型
type MathFunction = (a: number, b: number) => number;

// 基本运算函数
const add: MathFunction = (a, b) => a + b;
const subtract: MathFunction = (a, b) => a - b;
const multiply: MathFunction = (a, b) => a * b;
const divide: MathFunction = (a, b) => {
  if (b === 0) {
    throw new Error("Division by zero");
  }
  return a / b;
};

// 计算器函数
function calculate(
  operation: MathFunction,
  ...numbers: number[]
): number {
  if (numbers.length === 0) {
    return 0;
  }
  
  return numbers.reduce((result, num) => operation(result, num));
}

// 使用示例
console.log(calculate(add, 1, 2, 3, 4)); // 10
console.log(calculate(multiply, 2, 3, 4)); // 24
console.log(calculate(divide, 100, 2, 5)); // 10

示例 3:数据处理函数

typescript
// 定义数据处理函数类型
type DataProcessor<T, R> = (data: T) => R;
type FilterFunction<T> = (item: T) => boolean;
type MapFunction<T, R> = (item: T) => R;

// 数组过滤函数
function filterArray<T>(
  array: T[],
  predicate: FilterFunction<T>
): T[] {
  return array.filter(predicate);
}

// 数组映射函数
function mapArray<T, R>(
  array: T[],
  mapper: MapFunction<T, R>
): R[] {
  return array.map(mapper);
}

// 数组归约函数
function reduceArray<T, R>(
  array: T[],
  reducer: (accumulator: R, item: T) => R,
  initialValue: R
): R {
  return array.reduce(reducer, initialValue);
}

// 使用示例
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 过滤偶数
const evens = filterArray(numbers, (n) => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]

// 映射为平方
const squares = mapArray(numbers, (n) => n * n);
console.log(squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

// 计算总和
const sum = reduceArray(numbers, (acc, n) => acc + n, 0);
console.log(sum); // 55

示例 4:回调函数类型

typescript
// 定义回调函数类型
type SuccessCallback<T> = (data: T) => void;
type ErrorCallback = (error: Error) => void;

// 异步数据获取函数
function fetchData<T>(
  url: string,
  onSuccess: SuccessCallback<T>,
  onError: ErrorCallback
): void {
  // 模拟异步操作
  setTimeout(() => {
    try {
      // 模拟成功情况
      const data = { message: "Data fetched successfully" } as T;
      onSuccess(data);
    } catch (error) {
      onError(error instanceof Error ? error : new Error(String(error)));
    }
  }, 1000);
}

// 使用示例
fetchData<{ message: string }>(
  "https://api.example.com/data",
  (data) => {
    console.log("Success:", data.message);
  },
  (error) => {
    console.error("Error:", error.message);
  }
);

函数类型作为参数

函数可以作为参数传递给其他函数:

typescript
// 函数类型作为参数
function processNumbers(
  numbers: number[],
  processor: (n: number) => number
): number[] {
  return numbers.map(processor);
}

// 使用示例
const numbers = [1, 2, 3, 4, 5];

// 传入不同的处理函数
const doubled = processNumbers(numbers, (n) => n * 2);
const squared = processNumbers(numbers, (n) => n * n);
const incremented = processNumbers(numbers, (n) => n + 1);

console.log(doubled); // [2, 4, 6, 8, 10]
console.log(squared); // [1, 4, 9, 16, 25]
console.log(incremented); // [2, 3, 4, 5, 6]

类型检查示例

常见错误

typescript
// ❌ 错误:参数类型不匹配
function greet(name: string): string {
  return `Hello, ${name}!`;
}
greet(123); // Error: Argument of type 'number' is not assignable to parameter of type 'string'

// ❌ 错误:缺少必需参数
function createUser(name: string, age: number): void {
  console.log(`User: ${name}, Age: ${age}`);
}
createUser("Alice"); // Error: Expected 2 arguments, but got 1

// ❌ 错误:返回值类型不匹配
function add(a: number, b: number): number {
  return `${a + b}`; // Error: Type 'string' is not assignable to type 'number'
}

// ❌ 错误:可选参数位置错误
function badFunction(optional?: string, required: string) {
  // Error: A required parameter cannot follow an optional parameter
}

正确写法

typescript
// ✅ 正确:参数类型匹配
function greet(name: string): string {
  return `Hello, ${name}!`;
}
greet("Alice"); // "Hello, Alice!"

// ✅ 正确:提供所有必需参数
function createUser(name: string, age: number): void {
  console.log(`User: ${name}, Age: ${age}`);
}
createUser("Alice", 25);

// ✅ 正确:返回值类型匹配
function add(a: number, b: number): number {
  return a + b;
}

// ✅ 正确:可选参数在必需参数之后
function goodFunction(required: string, optional?: string) {
  console.log(required, optional);
}

注意事项

提示

  • 虽然 TypeScript 可以推断函数返回类型,但显式声明返回类型可以让代码更清晰,也便于发现类型错误
  • 使用函数类型别名可以提高代码的可读性和可维护性
  • 可选参数和默认参数在功能上类似,但使用场景不同:可选参数用于"可能不提供"的情况,默认参数用于"有默认值"的情况

注意

  • 可选参数必须放在必需参数之后,否则会出现编译错误
  • 剩余参数必须放在所有参数的最后
  • 有默认值的参数在类型上等同于可选参数,但不需要使用 ? 标记
  • 可选参数在函数内部可能是 undefined,使用前应该进行检查

重要

  • 函数类型检查发生在编译时,不会影响运行时的性能
  • 箭头函数和普通函数在类型系统上基本相同,但在 this 绑定上有区别(将在后续章节讨论)
  • 函数类型是 TypeScript 类型系统的基础,理解函数类型对于学习泛型、函数重载等高级概念非常重要

信息

函数类型与对象类型的关系

  • 函数在 TypeScript 中也是对象,可以赋值给变量
  • 函数类型可以使用对象类型语法:{ (param: type): returnType }
  • 但更常用的是箭头函数语法:(param: type) => returnType

相关链接

基于 VitePress 构建