一个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 方法?
首先我知道的几个方案:
- 继承, 直接让LRU 继承 EventEmitter 即可,这样能识别。但是我不想这样做,两者并无实际关系,继承不太合适。
- 在 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 {}
回复
1个回答

test
2024-06-26
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(); // 不再报错
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容