宜都市纤凝网

TypeScript中使用回调函数的实现

2026-04-11 09:48:02 浏览次数:4
详细信息

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,因为它们提供了更清晰、更易维护的代码结构。

相关推荐