一个typescript动态给实例添加方法后如何能让实例识别到方法的问题?

有个 EventEmitter 类,其 installTo 核心部分摘要如下,主要作用是在目标对象中添加 'on', 'off', 'emit', 'fire', 'once' 方法。

class EventEmitter {
  static installTo(obj: object): void {
    const eventEmitter = new EventEmitter();
    const methods = ['on', 'off', 'emit', 'fire', 'once'];
    methods.forEach((method) => {
      Object.defineProperty(obj, method, {
        value: (eventEmitter as { [key: string]: any })[method],
        enumerable: false,
        writable: false,
        configurable: false,
      });
    });
  }
}

现有一个 LRU 类,其构造函数中 通过 EventEmitter.installTo(this) 将 EventEmitter 的方法添加到 LRU 实例中,部分代码如下:

class LRU {
  constructor(options?: number | LRUOptions) {
    EventEmitter.installTo(this); // 当然这里是可以做成一个装饰器的,但与此问题无关。
  }
}

此时 ts 中以下代码将会报错

const lru = new LRU(10)
lr.on('xxx') // 提示:Property 'on' does not exist on type 'LRU'

我该如何处理让 LRU 的示例上能正确识别出 on 方法?


首先我知道的几个方案:

  1. 继承, 直接让LRU 继承 EventEmitter 即可,这样能识别。但是我不想这样做,两者并无实际关系,继承不太合适。
  2. 在 LRU 类里面直接写 on = EventEmitter.prototype.on; 等类似的代码,这样实际是额外再给LRU的实例上加了这些方法的引用。但这样,1是和EventEmitter.installTo有重复(内部还有其他细节处理逻辑)2是代码有耦合。

请问有什么办法能处理这个问题吗? 初使用typescript,可能对此不熟悉,如有好的方案请指出。


感谢乔治的答案。

最终解决方案,如下:

// 从EventEmitter 中获取需要的方法
type EventEmitterMethods  = Pick<EventEmitter, 'on' | 'off' | 'emit' | 'once' |'fire'>;

// LRU 实现省略
class LRU {}
// 声明合并
interface LRU extends EventEmitterMethods {}
阅读 310
1 个回答

class EventEmitter {
    static installTo(obj: object): void {
        //...
    }
    on() { /* ... */ }
    off() { /* ... */ }
    emit() { /* ... */ }
    fire() { /* ... */ }
    once() { /* ... */ }
}


interface EventEmitterMethods {
    on(): void;
    off(): void;
    emit(): void;
    fire(): void;
    once(): void;
}

// 定义LRU类
class LRU {
    constructor(options?: number | LRUOptions) {
        EventEmitter.installTo(this);
    }
}

// 用声明合并把EventEmitterMethods接口与LRU类合在一起
interface LRU extends EventEmitterMethods { }

const lru = new LRU();
lru.on(); // 不再报错
推荐问题
logo
Microsoft
子站问答
访问
宣传栏