TypeScript中列表包装类EventList使用forEach方法报错问题
问题:实现Iterable接口的EventList无法调用forEach方法
我将普通数组替换为自定义的可监听列表EventList后,调用forEach时出现错误:
Property 'forEach' does not exist on type 'EventList
'.
示例代码:
let numberList = new EventList<number>([1,2,3,4]); numberList.forEach((element: number) => console.log(element));
我原本以为实现Iterable接口后会自动拥有forEach方法,以下是EventList的实现代码:
export class EventList<T> implements Iterable<T>{ private list: T[] = []; private changeListener: ((list: T[]) => void)[] = []; constructor(items: T[] = []) { this.list = items; } public push(element: T): void { this.list.push(element); this.emitChange(); } public splice(index: number, deletCount?: number) { this.list.splice(index, deletCount); this.emitChange(); } public onChange(callback: (list: T[]) => void) { this.changeListener.push(callback); } [Symbol.iterator](): Iterator<T> { let currIndex = 0; const items = this.list; return { next(): IteratorResult<T> { if(currIndex < items.length) { return { done: false, value: items[currIndex++] }; } else { return { done: true, value: null }; } } }; } private emitChange(): void { for (const listener of this.changeListener) { listener(this.list); } } }
原因分析
Iterable接口只要求类实现[Symbol.iterator]方法,让对象支持for...of遍历,但数组的forEach方法并不是Iterable接口的成员——它是Array.prototype上的专属方法。自定义类即使实现了Iterable,也不会自动获得forEach。
解决方案
方案1:手动实现forEach方法
直接在EventList中添加forEach方法,内部调用底层数组的forEach即可:
export class EventList<T> implements Iterable<T>{ // ... 原有代码 ... public forEach(callback: (element: T, index: number, array: T[]) => void): void { this.list.forEach(callback); } // ... 原有代码 ... }
这样就能直接调用numberList.forEach(...),行为和数组的forEach完全一致。
方案2:继承Array类
如果希望EventList拥有所有数组方法(包括forEach、map、filter等),可以让EventList继承Array
export class EventList<T> extends Array<T> { private changeListener: ((list: T[]) => void)[] = []; constructor(items: T[] = []) { super(...items); } public push(...elements: T[]): number { const result = super.push(...elements); this.emitChange(); return result; } public splice(start: number, deleteCount?: number, ...items: T[]): T[] { const result = super.splice(start, deleteCount, ...items); this.emitChange(); return result; } public onChange(callback: (list: T[]) => void) { this.changeListener.push(callback); } private emitChange(): void { for (const listener of this.changeListener) { listener(this); } } }
这种方式无需手动实现每个数组方法,但要注意重写所有会修改数组的方法(如pop、shift、unshift等),确保修改时能触发监听回调。
方案3:临时转换为数组(不推荐)
如果只是临时需要forEach,可以将EventList转换为数组后调用:
Array.from(numberList).forEach((element: number) => console.log(element)); // 或者展开运算符 [...numberList].forEach((element: number) => console.log(element));
但这种方式每次都要转换数组,不够高效,也不够直观。
内容的提问来源于stack exchange,提问作者Molitoris
相关产品推荐
相关产品推荐

