发布订阅模式ts写法记录

74 阅读1分钟
// 事件类型定义(使用元组类型)
interface UploaderEventMap {
  [key: string]: any[]; // 索引签名
  "taskAdd": [tasks: UTask[]];
  "taskComplete": [task: UTask];
  "taskError": [error: UErrorEvent, retry: () => void];
  "taskCancel": [task: UTask, reason: string];
  "taskProgress": [progress: UProgressEvent];
}

class EventEmitter<T extends Record<string, any[]>> {
  private callbacks = new Map<keyof T, Array<(...args: any[]) => void>>();

  // 类型安全的事件监听方法
  on<K extends keyof T>(
    eventName: K,
    callback: (...args: T[K]) => void
  ): this {
    const existing = this.callbacks.get(eventName) || [];
    existing.push(callback);
    this.callbacks.set(eventName, existing);
    return this;
  }

  // 改进后的emit方法(支持多参数)
  emit<K extends keyof T>(eventName: K, ...args: T[K]): this {
    const callbacks = this.callbacks.get(eventName);
    if (callbacks) {
      callbacks.forEach(callback => {
        callback(...args);
      });
    }
    return this;
  }
}

// 使用示例
const uploader = new EventEmitter<UploaderEventMap>();

// 注册事件监听(自动推断参数类型)
uploader.on("taskError", (error, retry) => {
  console.error(error.message);
  retry();
});

// 触发事件(类型安全检查)
uploader.emit("taskError", 
  { error: new Error("Upload failed"), task: {} as UTask },
  () => console.log("Retrying...")
);

// 类型错误示例(TS会报错)
uploader.emit("taskProgress"); // ❌ 缺少参数
uploader.emit("taskCancel", {} as UTask); // ❌ 缺少第二个参数

进阶优化方案:

1. 异步事件支持

class AsyncEventEmitter<T extends Record<string, any[]>> {
  async emitAsync<K extends keyof T>(
    eventName: K, 
    ...args: T[K]
  ): Promise<void> {
    const callbacks = this.callbacks.get(eventName) || [];
    await Promise.all(callbacks.map(cb => cb(...args)));
  }
}

// 使用示例
await uploader.emitAsync("beforeUpload", task);

2. 优先级控制

interface CallbackWithPriority {
  priority: number;
  callback: (...args: any[]) => void;
}

class PriorityEventEmitter<T extends Record<string, any[]>> {
  private callbacks = new Map<keyof T, CallbackWithPriority[]>();

  on<K extends keyof T>(
    eventName: K,
    callback: (...args: T[K]) => void,
    priority = 0
  ): this {
    const existing = this.callbacks.get(eventName) || [];
    existing.push({ priority, callback });
    existing.sort((a, b) => b.priority - a.priority);
    this.callbacks.set(eventName, existing);
    return this;
  }
}

3. 一次事件监听

once<K extends keyof T>(
  eventName: K,
  callback: (...args: T[K]) => void
): this {
  const wrapper = (...args: T[K]) => {
    callback(...args);
    this.off(eventName, wrapper);
  };
  return this.on(eventName, wrapper);
}

类型安全验证机制:

  1. 参数数量校验

    uploader.emit("taskCancel", task); // ❌ 缺少第二个参数
    
  2. 参数类型校验

    uploader.emit("taskError", "error string", () => {}); // ❌ 第一个参数类型错误
    
  3. 事件名称校验

    uploader.on("unknownEvent", () => {}); // ❌ 未知事件类型
    

该方案通过 TypeScript 的类型系统实现了:

  1. 动态参数数量支持
  2. 严格的参数类型检查
  3. 自动类型推断
  4. 可扩展的事件架构

适用于需要处理复杂事件参数的场景,如文件上传管理器、游戏事件系统等,确保在开发阶段即可捕获参数类型错误。

内容为AI生成