函数是TypeScript应用程序的基石。掌握函数的使用技巧,能让你写出更健壮、更易维护的代码。本文将带你深入理解TypeScript函数的各种特性。
一、函数基础:两种定义方式
TypeScript支持JavaScript的两种函数定义方式:命名函数和匿名函数。
typescript
// 1. 命名函数
function greet(name: string): string {
return `Hello, ${name}!`;
}
// 2. 匿名函数(函数表达式)
const greet2 = function(name: string): string {
return `Hello, ${name}!`;
};
在实际开发中,选择哪种方式取决于使用场景:
- 命名函数:适合主要功能、工具函数
- 匿名函数:适合回调函数、一次性使用的函数
二、函数类型:确保输入输出安全
TypeScript的强大之处在于它能精确控制函数的输入和输出类型。
基本类型注解
typescript
// 参数类型和返回值类型
function add(x: number, y: number): number {
return x + y;
}
完整函数类型
当需要将函数赋值给变量时,我们可以使用完整函数类型声明:
typescript
// 完整函数类型
const myAdd: (base: number, increment: number) => number =
function(x: number, y: number): number {
return x + y;
};
这种写法虽然略显冗长,但在复杂项目中能提高代码可读性。
三、灵活参数处理技巧
可选参数:处理非必填项
在实际业务中,我们经常遇到非必填参数的情况:
typescript
function buildFullName(firstName: string, lastName?: string): string {
return lastName ? `${firstName} ${lastName}` : firstName;
}
console.log(buildFullName('张', '三')); // 张 三
console.log(buildFullName('李')); // 李
重要规则:
- 可选参数必须位于必选参数之后
- 可选参数不能出现在必选参数前面
默认参数:智能填充缺省值
当参数未传递时,使用默认值:
typescript
function createGreeting(name: string, greeting: string = 'Hello'): string {
return `${greeting}, ${name}!`;
}
console.log(createGreeting('Alice')); // Hello, Alice!
console.log(createGreeting('Bob', 'Hi')); // Hi, Bob!
最佳实践:
- 默认参数可以放在任何位置,但建议放在参数列表末尾
- 默认值可以是表达式,甚至是函数调用
剩余参数:处理可变参数列表
当参数数量不确定时,可以使用剩余参数语法:
typescript
function assembleCar(make: string, ...features: string[]): string {
return `制造:${make},配置:${features.join('、')}`;
}
console.log(assembleCar('特斯拉', '自动驾驶', '全景天窗'));
// 制造:特斯拉,配置:自动驾驶、全景天窗
技术要点:
- 剩余参数必须是参数列表中的最后一个
- 一个函数只能有一个剩余参数
- 剩余参数会被当作数组处理
四、函数重载:处理复杂场景的利器
当函数需要处理多种参数类型时,函数重载提供了完美的解决方案。
实际案例:用户信息处理
假设我们需要一个函数,既能处理用户ID(number),也能处理用户名(string):
typescript
// 重载声明
function getUserInfo(id: number): string;
function getUserInfo(name: string): string;
// 函数实现
function getUserInfo(info: string | number): string {
if (typeof info === 'number') {
return `用户ID:${info}`;
} else {
return `用户名:${info}`;
}
}
console.log(getUserInfo(1001)); // 用户ID:1001
console.log(getUserInfo('Alice')); // 用户名:Alice
复杂案例:API响应处理
处理不同状态码的API响应:
typescript
// 重载声明
function handleResponse(code: 200, data: string): void;
function handleResponse(code: 400, error: string): void;
function handleResponse(code: 500, error: string, details: string): void;
// 函数实现
function handleResponse(code: number, message: string, details?: string): void {
switch(code) {
case 200:
console.log(`成功:${message}`);
break;
case 400:
console.log(`客户端错误:${message}`);
break;
case 500:
console.log(`服务器错误:${message},详情:${details}`);
break;
}
}
handleResponse(200, '操作成功');
handleResponse(400, '无效请求');
handleResponse(500, '内部错误', '数据库连接失败');
重载规则:
- 重载声明必须紧挨着函数实现
- 重载声明中不能包含函数体
- 函数实现必须兼容所有重载声明
五、高级技巧:函数类型进阶
箭头函数的类型
typescript
const calculate: (x: number, y: number) => number =
(a, b) => a * b;
回调函数类型安全
typescript
function fetchData(callback: (data: string) => void): void {
// 模拟异步操作
setTimeout(() => callback('数据加载完成'), 1000);
}
fetchData(result => console.log(result));
函数类型作为参数
typescript
function processNumbers(
numbers: number[],
processor: (n: number) => number
): number[] {
return numbers.map(processor);
}
const doubled = processNumbers([1, 2, 3], n => n * 2);
console.log(doubled); // [2, 4, 6]
六、最佳实践:编写高质量函数
- 单一职责原则:每个函数只做一件事
- 合理命名:函数名应准确描述其功能
- 控制参数数量:建议不超过3个参数
- 明确返回值:避免返回混合类型
- 使用重载代替复杂类型判断:提高可读性
七、实战应用场景
场景1:表单验证函数
typescript
// 重载声明
function validateInput(value: string, maxLength: number): boolean;
function validateInput(value: number, min: number, max: number): boolean;
// 函数实现
function validateInput(
value: string | number,
minOrMax: number,
max?: number
): boolean {
if (typeof value === 'string') {
return value.length <= minOrMax;
} else {
return value >= minOrMax && value <= (max as number);
}
}
console.log(validateInput('hello', 10)); // true
console.log(validateInput(15, 10, 20)); // true
console.log(validateInput(25, 10, 20)); // false
场景2:API请求函数
typescript
async function fetchAPI(
endpoint: string,
method: 'GET' | 'POST' = 'GET',
body?: object
): Promise<any> {
const options: RequestInit = {
method,
headers: { 'Content-Type': 'application/json' }
};
if (body) {
options.body = JSON.stringify(body);
}
const response = await fetch(endpoint, options);
return response.json();
}
// 使用示例
const userData = await fetchAPI('/api/users/1');
const updateResult = await fetchAPI('/api/users/1', 'POST', { name: '新名字' });