函数类型
概述
函数类型(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