I'm trying to get this working JavaScript (but not mine :P) pass typescript type checking. Maybe it's just late in the day but I could use some help.
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);
}
I'd try to simplify the code but I'm not sure I understand the error. I see 2 errors actually. One is, typescript seems confused about this
inside next
. I complains about this.registry
not existing
The other is
(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)
I tried to fix the first one by moving next
up like this
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);
}
That solves the first error but not the second
CodePudding user response:
Referencing a separate this.registry
as a custom value on an iterator object is odd and can cause problems. It'd be easier to ditch that entirely and just use an arrow function and the outer this
. That way, the typing for it will just work - your arrow function is the right idea.
next: () => {
while (i < this.objects.length) {
const obj = this.objects[i ].deref();
// ...
After that, there's just one more warning due to the typing here:
[Symbol.iterator](): IterableIterator<CaptureState> {
which can be fixed by specifying that the this
is the same as the class that was instantiated, and letting TypeScript infer the iterator type on its own.
[Symbol.iterator](this: ObjectRegistry<GPUType, CaptureState>) {
The
Property 'value' is optional in type '{ done: true; value?: undefined; }' but required in type 'IteratorReturnResult'.(2322)
can be fixed by changing
return { done: true };
to
return { done: true, value: undefined };
but doesn't look necessary.