1. 基本回调函数定义
定义回调类型
// 方式1:使用类型别名
type Callback = (result: string) => void;
// 方式2:使用接口
interface CallbackInterface {
(error: Error | null, data: any): void;
}
// 方式3:泛型回调
type GenericCallback<T> = (data: T) => void;
使用回调函数
// 异步操作的回调示例
function fetchData(callback: (data: string) => void): void {
setTimeout(() => {
callback('Data fetched successfully');
}, 1000);
}
// 使用
fetchData((data) => {
console.log(data); // "Data fetched successfully"
});
// 带错误处理的回调
function readFile(filename: string, callback: (error: Error | null, data?: string) => void): void {
if (filename === 'error.txt') {
callback(new Error('File not found'));
} else {
callback(null, 'File content');
}
}
readFile('test.txt', (error, data) => {
if (error) {
console.error('Error:', error.message);
return;
}
console.log('Data:', data);
});
2. 可选参数和默认值
function processUser(
userId: number,
callback?: (user: { id: number; name: string }) => void
): void {
const user = { id: userId, name: 'John Doe' };
if (callback) {
callback(user);
} else {
console.log('Default processing:', user);
}
}
// 使用可选回调
processUser(1); // 使用默认处理
processUser(2, (user) => {
console.log('Custom processing:', user);
});
3. 回调函数中的 this 类型
interface User {
id: number;
name: string;
greet(callback: (this: User, message: string) => void): void;
}
const user: User = {
id: 1,
name: 'Alice',
greet(callback) {
callback.call(this, `Hello, I'm ${this.name}`);
}
};
user.greet(function(this: User, message) {
console.log(`${message} with ID: ${this.id}`);
});
4. 高阶函数中的回调
// 接收回调作为参数的高阶函数
function withRetry<T>(
operation: (callback: (result: T) => void) => void,
maxRetries: number = 3,
onComplete: (result: T | null, error?: Error) => void
): void {
let retries = 0;
function attempt() {
operation((result) => {
onComplete(result);
}, (error) => {
retries++;
if (retries < maxRetries) {
console.log(`Retrying... (${retries}/${maxRetries})`);
attempt();
} else {
onComplete(null, error);
}
});
}
attempt();
}
5. 回调地狱的解决方案
传统回调方式(不推荐)
function callbackHell() {
getUser(1, (user) => {
getPosts(user.id, (posts) => {
getComments(posts[0].id, (comments) => {
console.log(comments);
}, (error) => console.error(error));
}, (error) => console.error(error));
}, (error) => console.error(error));
}
使用 Promise 包装回调
// 将回调函数转换为 Promise
function promisify<T>(
fn: (...args: any[]) => void
): (...args: any[]) => Promise<T> {
return (...args: any[]) => {
return new Promise<T>((resolve, reject) => {
fn(...args, (error: Error | null, result: T) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
}
// 示例
const readFilePromise = promisify<string>(readFile);
async function processFiles() {
try {
const data = await readFilePromise('test.txt');
console.log(data);
} catch (error) {
console.error(error);
}
}
6. 事件处理中的回调
// 事件发射器示例
type EventCallback<T> = (data: T) => void;
class EventEmitter<T> {
private events: Map<string, EventCallback<T>[]> = new Map();
on(event: string, callback: EventCallback<T>): void {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event)!.push(callback);
}
emit(event: string, data: T): void {
const callbacks = this.events.get(event);
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
}
// 使用
const emitter = new EventEmitter<string>();
emitter.on('message', (data) => {
console.log('Received:', data);
});
emitter.emit('message', 'Hello World');
7. 实际应用示例
// 数据库操作示例
interface User {
id: number;
name: string;
email: string;
}
class Database {
private users: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
];
findUserById(
id: number,
callback: (error: Error | null, user?: User) => void
): void {
setTimeout(() => {
const user = this.users.find(u => u.id === id);
if (user) {
callback(null, user);
} else {
callback(new Error('User not found'));
}
}, 500);
}
// 并行处理多个回调
findUsersByIds(
ids: number[],
callback: (error: Error | null, users?: User[]) => void
): void {
const results: User[] = [];
let pending = ids.length;
let hasError = false;
ids.forEach(id => {
this.findUserById(id, (error, user) => {
if (hasError) return;
if (error) {
hasError = true;
callback(error);
return;
}
if (user) results.push(user);
pending--;
if (pending === 0) {
callback(null, results);
}
});
});
}
}
// 使用
const db = new Database();
db.findUsersByIds([1, 2], (error, users) => {
if (error) {
console.error(error.message);
return;
}
console.log('Found users:', users);
});
最佳实践建议
始终声明回调参数类型:避免使用
any
使用可选参数处理可选回调
考虑错误优先的回调模式:
(error, data) => void
避免回调地狱:使用 Promise 或 async/await
考虑性能:避免在循环中创建新的回调函数
清晰的错误处理:确保回调包含错误处理路径
在现代 TypeScript 开发中,虽然回调函数仍然有用,但通常推荐优先使用 Promise 和 async/await,因为它们提供了更清晰、更易维护的代码结构。