You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript类Mixin自动生成与链式调用优化技术问询

TypeScript事件Mixin优化方案

基础代码

interface BaseEvent {
    type: string;
    payload: any;
}

interface EventEmitter {
    emit(event: BaseEvent): void;
}

class BaseClass {
    constructor(protected eventEmitter: EventEmitter) {}

    emit(event: BaseEvent) {
        this.eventEmitter.emit(event);
    }
}

interface CustomEvent1 extends BaseEvent {
    type: 'custom1';
    payload: {
        message: string;
    };
}

interface CustomEvent2 extends BaseEvent {
    type: 'custom2';
    payload: {
        value: number;
    };
}

const eventEmitter: EventEmitter = {
    emit(event: BaseEvent) {
        console.log(`Event type: ${event.type}, payload:`, event.payload);
    },
};

当前Mixin实现代码

type Constructor<T> = new (...args: any[]) => T;

function producesCustomEvent1<TBase extends Constructor<BaseClass>>(Base: TBase) {
    return class extends Base {
        emitCustomEvent1(event: CustomEvent1) {
            this.emit(event);
        }
    };
}

function producesCustomEvent2<TBase extends Constructor<BaseClass>>(Base: TBase) {
    return class extends Base {
        emitCustomEvent2(event: CustomEvent2) {
            this.emit(event);
        }
    };
}

class CustomEventEmitter extends producesCustomEvent1(producesCustomEvent2(BaseClass)) {
    constructor(eventEmitter: EventEmitter) {
        super(eventEmitter);
    }
}


const eventEmitter: EventEmitter = {
    emit(event: BaseEvent) {
        console.log(`Event type: ${event.type}, payload:`, event.payload);
    },
};

const customEventEmitter = new CustomEventEmitter(eventEmitter);

const event1: CustomEvent1 = { type: 'custom1', payload: { message: 'Hello, world!' } };
customEventEmitter.emitCustomEvent1(event1); // Output: "Event type: custom1, payload: { message: 'Hello, world!' }"

const event2: CustomEvent2 = { type: 'custom2', payload: { value: 42 } };
customEventEmitter.emitCustomEvent2(event2); // Output: "Event type: custom2, payload: { value: 42 }"

存在的问题

  • 核心问题:每次新增事件类型时都需要编写几乎完全相同的Mixin,希望通过createEventMixin<CustomEvent1>()自动生成对应的emitCustomEvent1方法
  • 语法问题:多层Mixin嵌套写法(如producesCustomEvent1(producesCustomEvent2(BaseClass)))在事件数量增多时可读性极差,希望采用链式Builder风格(如Builder(BaseClass).withProducingEvent1().withProducingEvent2().return())构建类

解决方案

问题1:自动生成通用事件Mixin

利用TypeScript泛型和类型推断,可以实现一个通用的Mixin生成函数,根据事件的type属性自动生成对应的发射方法,无需重复编写模板代码。

实现思路

  1. 通过类型工具将事件的type(如custom1)转换为目标方法名(如emitCustomEvent1)
  2. 编写通用函数,接受事件类型参数,动态生成包含对应发射方法的Mixin类

代码实现

type Constructor<T> = new (...args: any[]) => T;

// 类型工具:将事件type转换为对应方法名(custom1 → emitCustomEvent1)
type EventMethodName<E extends BaseEvent> = `emitCustomEvent${E['type'] extends `custom${infer N}` ? N : never}`;

// 通用事件Mixin生成函数
function createEventMixin<E extends BaseEvent>(eventType: E['type']) {
  return function <TBase extends Constructor<BaseClass>>(Base: TBase) {
    return class extends Base {
      [key: EventMethodName<E>](event: E) {
        this.emit(event);
      }
    } as TBase & Record<EventMethodName<E>, (event: E) => void>;
  };
}

使用方式

新增事件时,只需一行代码生成对应的Mixin:

const producesCustomEvent1 = createEventMixin<CustomEvent1>('custom1');
const producesCustomEvent2 = createEventMixin<CustomEvent2>('custom2');

问题2:链式Builder风格构建类

封装一个Builder类,通过链式调用逐个应用Mixin,最终返回合并后的类,彻底解决嵌套可读性问题。

实现思路

  1. Builder类维护当前的基础类实例
  2. 提供链式方法,每次调用都将对应的Mixin应用到当前类上
  3. 最后通过return()方法输出最终构建完成的类

代码实现

class EventEmitterBuilder<TBase extends Constructor<BaseClass>> {
  private currentClass: TBase;

  constructor(baseClass: TBase) {
    this.currentClass = baseClass;
  }

  // 通用方法:添加任意事件类型的Mixin
  withEvent<E extends BaseEvent>(eventType: E['type']) {
    const mixin = createEventMixin<E>(eventType);
    this.currentClass = mixin(this.currentClass) as TBase & Record<EventMethodName<E>, (event: E) => void>;
    return this as unknown as EventEmitterBuilder<typeof this.currentClass>;
  }

  // 语法糖方法:针对特定事件的快捷调用(可选,进一步提升可读性)
  withCustomEvent1() {
    return this.withEvent<CustomEvent1>('custom1');
  }

  withCustomEvent2() {
    return this.withEvent<CustomEvent2>('custom2');
  }

  // 返回最终构建的类
  return() {
    return this.currentClass;
  }
}

// Builder入口函数
function Builder(baseClass: Constructor<BaseClass>) {
  return new EventEmitterBuilder(baseClass);
}

使用方式

通过链式调用轻松组合多个事件Mixin:

const CustomEventEmitter = Builder(BaseClass)
  .withCustomEvent1()
  .withCustomEvent2()
  .return();

完整可运行代码

interface BaseEvent {
  type: string;
  payload: any;
}

interface EventEmitter {
  emit(event: BaseEvent): void;
}

class BaseClass {
  constructor(protected eventEmitter: EventEmitter) {}

  emit(event: BaseEvent) {
    this.eventEmitter.emit(event);
  }
}

interface CustomEvent1 extends BaseEvent {
  type: 'custom1';
  payload: {
    message: string;
  };
}

interface CustomEvent2 extends BaseEvent {
  type: 'custom2';
  payload: {
    value: number;
  };
}

const eventEmitter: EventEmitter = {
  emit(event: BaseEvent) {
    console.log(`Event type: ${event.type}, payload:`, event.payload);
  },
};

// 优化后的Mixin与Builder实现
type Constructor<T> = new (...args: any[]) => T;
type EventMethodName<E extends BaseEvent> = `emitCustomEvent${E['type'] extends `custom${infer N}` ? N : never}`;

function createEventMixin<E extends BaseEvent>(eventType: E['type']) {
  return function <TBase extends Constructor<BaseClass>>(Base: TBase) {
    return class extends Base {
      [key: EventMethodName<E>](event: E) {
        this.emit(event);
      }
    } as TBase & Record<EventMethodName<E>, (event: E) => void>;
  };
}

class EventEmitterBuilder<TBase extends Constructor<BaseClass>> {
  private currentClass: TBase;

  constructor(baseClass: TBase) {
    this.currentClass = baseClass;
  }

  withEvent<E extends BaseEvent>(eventType: E['type']) {
    const mixin = createEventMixin<E>(eventType);
    this.currentClass = mixin(this.currentClass) as TBase & Record<EventMethodName<E>, (event: E) => void>;
    return this as unknown as EventEmitterBuilder<typeof this.currentClass>;
  }

  withCustomEvent1() {
    return this.withEvent<CustomEvent1>('custom1');
  }

  withCustomEvent2() {
    return this.withEvent<CustomEvent2>('custom2');
  }

  return() {
    return this.currentClass;
  }
}

function Builder(baseClass: Constructor<BaseClass>) {
  return new EventEmitterBuilder(baseClass);
}

// 构建并测试
const CustomEventEmitter = Builder(BaseClass)
  .withCustomEvent1()
  .withCustomEvent2()
  .return();

const customEventEmitter = new CustomEventEmitter(eventEmitter);

const event1: CustomEvent1 = { type: 'custom1', payload: { message: 'Hello, world!' } };
customEventEmitter.emitCustomEvent1(event1); // 输出: Event type: custom1, payload: { message: 'Hello, world!' }

const event2: CustomEvent2 = { type: 'custom2', payload: { value: 42 } };
customEventEmitter.emitCustomEvent2(event2); // 输出: Event type: custom2, payload: { value: 42 }

内容的提问来源于stack exchange,提问作者twilker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 10:09:54