I am attempting to parameterize a function within a Typescript class that returns a Promise. After the completion of the promise, I return this
, which is then used polymorphically by the caller. However, I am encountering a compile-time error that I am struggling to comprehend.
The following simplified code compiles without any issues:
class foo {
aFoo(): Promise<foo> {
return new Promise<foo>(resolve => resolve(this));
}
}
class bar extends foo {
test() {
this.aFoo().then(result => {
let val: bar;
val = result as bar;
});
}
}
Despite this working solution, I aim to avoid having to downcast results, such as with val = result as bar
, every time I call this function. Hence, my attempt to parameterize the function in the superclass:
class foo {
aFoo<T extends foo>(): Promise<T> {
return new Promise<T>(resolve => resolve(this));
}
}
class bar extends foo {
test() {
this.aFoo<bar>().then(result => {
let val: bar;
val = result;
});
}
}
However, I am facing a compiler error on resolve(this)
in the promise returned from aFoo
.
The error message states:
this: this
Argument of type 'this' is not assignable to parameter of type 'T | PromiseLike<T> | undefined'.
Type 'foo' is not assignable to type 'T | PromiseLike<T> | undefined'.
Type 'foo' is not assignable to type 'PromiseLike<T>'.
Type 'this' is not assignable to type 'PromiseLike<T>'.
Property 'then' is missing in type 'foo' but required in type 'PromiseLike<T>'.ts(2345)
lib.es5.d.ts(1393, 5): 'then' is declared here.
To suppress the compiler error, I can utilize some redundant casting:
return new Promise<foo>(resolve => resolve((this as unknown) as T));
While using this workaround does solve the issue, I would like to gain an understanding of why the compiler is raising concerns. Initially, I thought it might be connected to the complexities of this
in JS/TS, yet even converting this
into an arrow function did not eliminate the error. Additionally, the error seems peculiar to me, as it describes this
as a type rather than an instance - although I acknowledge that this
can indeed be utilized within a type context in TS. Any insights into where I may have erred?