如何在TypeScript中为Symbol Iterator实现添加正确类型
我正尝试让一段别人写的可用JavaScript代码通过TypeScript类型检查,遇到了两个问题,以下是详细情况:
原始代码
class GPUTexture {} class BaseState<T> { webgpuObject: T | null; constructor() { this.webgpuObject = null; } } class TextureState extends BaseState<GPUTexture> { name = "foo"; } interface CaptureStateBase<GPUType> { webgpuObject: GPUType | null; } class ObjectRegistry<GPUType extends Object, CaptureState extends CaptureStateBase<GPUType>> { iterating: boolean; dataMap: WeakMap<GPUType, CaptureState>; objects: WeakRef<GPUType>[]; constructor() { this.dataMap = new WeakMap(); this.objects = []; this.iterating = false; } add(obj: GPUType, data: CaptureState) { if (this.iterating) { throw new Error('Mutating Registry while iterating it.'); } this.dataMap.set(obj, data); this.objects.push(new WeakRef(obj)); data.webgpuObject = obj; } get(obj: GPUType) { return this.dataMap.get(obj); } [Symbol.iterator](): IterableIterator<CaptureState> { let i = 0; this.iterating = true; return { registry: this, next() { while (i < this.registry.objects.length) { const obj = this.registry.objects[i++].deref(); if (obj === undefined) { continue; } return { value: this.registry.get(obj), done: false }; } this.registry.iterating = false; return { done: true }; }, }; } } const textures = new ObjectRegistry<GPUTexture, TextureState>(); for (const tex of textures) { console.log(tex.name); }
遇到的错误
- TypeScript对
next方法内的this识别错误,提示this.registry不存在 - 迭代器返回值类型不匹配,具体错误信息:
(method) Iterator<CaptureState, any, undefined>.next(...args: [] | [undefined]): IteratorResult<CaptureState, any>
Type '() => { value: any; done: false; } | { done: true; value?: undefined; }' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<CaptureState, any>'.
Type '{ value: any; done: false; } | { done: true; value?: undefined; }' is not assignable to type 'IteratorResult<CaptureState, any>'.
Type '{ done: true; value?: undefined; }' is not assignable to type 'IteratorResult<CaptureState, any>'.
Type '{ done: true; value?: undefined; }' is not assignable to type 'IteratorReturnResult'.
Property 'value' is optional in type '{ done: true; value?: undefined; }' but required in type 'IteratorReturnResult'.(2322)
尝试修改后的代码
我把next方法抽出来定义,解决了第一个错误,但第二个错误依然存在:
class GPUTexture {} class BaseState<T> { webgpuObject: T | null; constructor() { this.webgpuObject = null; } } class TextureState extends BaseState<GPUTexture> { name = "foo"; } interface CaptureStateBase<GPUType> { webgpuObject: GPUType | null; } class ObjectRegistry<GPUType extends Object, CaptureState extends CaptureStateBase<GPUType>> { iterating: boolean; dataMap: WeakMap<GPUType, CaptureState>; objects: WeakRef<GPUType>[]; constructor() { this.dataMap = new WeakMap(); this.objects = []; this.iterating = false; } add(obj: GPUType, data: CaptureState) { if (this.iterating) { throw new Error('Mutating Registry while iterating it.'); } this.dataMap.set(obj, data); this.objects.push(new WeakRef(obj)); data.webgpuObject = obj; } get(obj: GPUType) { return this.dataMap.get(obj); } [Symbol.iterator](): IterableIterator<CaptureState> { let i = 0; this.iterating = true; const next = () => { while (i < this.objects.length) { const obj = this.objects[i++].deref(); if (obj === undefined) { continue; } return { value: this.get(obj), done: false }; } this.iterating = false; return { done: true }; }; return { next }; } } const textures = new ObjectRegistry<GPUTexture, TextureState>(); for (const tex of textures) { console.log(tex.name); }
内容的提问来源于stack exchange,提问作者user128511

