I want to create a versatile function that can handle sub-types of a base class and return a promise that resolves to an instance of the specified class. The code snippet below demonstrates my objective:
class foo {}
class bar extends foo {}
const someBar = new bar();
function foobar<T extends foo>(): Promise<T> {
return new Promise<T>(resolve => resolve(someBar)); // encountering compilation error
}
While I understand that TypeScript follows structural typing allowing any type for T in this simplified scenario, I am puzzled by why it won't allow me to return the value of someBar.
Is there a way to achieve this functionality? Thank you!
The compiler error message I'm facing reads:
const someBar: bar
Argument of type 'bar' is not assignable to parameter of type 'T | PromiseLike<T> | undefined'.
Property 'then' is missing in type 'bar' but required in type 'PromiseLike<T>'.ts(2345)
lib.es5.d.ts(1393, 5): 'then' is declared here.
Update
Upon request, I will provide additional context on what I aim to achieve. Below is functional code (I added functions to foo and bar for differentiation) that compiles without errors:
class foo {
f() {}
}
class bar extends foo {
b() {}
}
const someBar = new bar();
function foobar(): Promise<foo> {
return new Promise<foo>(resolve => resolve(someBar));
}
foobar().then(result => {
const myBar: bar = result as bar;
console.log(myBar);
});
I hoped to avoid the necessity of downcasting the polymorphic result of the promise as shown with const myBar: bar = result as bar
, illustrated below:
class foo {
f() {}
}
class bar extends foo {
b() {}
}
const someBar = new bar();
function foobar<T extends foo>(): Promise<T> {
return new Promise<T>(resolve => resolve(someBar));
}
foobar<bar>().then(result => {
const myBar: bar = result;
console.log(myBar);
});
TypeScript correctly deduces that result is a bar type, yet it restricts me from returning someBar within the function.
In cases where my generic class method dealt with this
, using the polymorphic this
was sufficient for achieving similar type checking - though I face a different scenario here outside of a class.
Update 2
This example does not necessarily require a promise to showcase my intent. Here's a further simplification (excluding foo and bar definitions since they remain unchanged):
function foobar<T extends Foo>(): T {
return someBar;
}
const mybar: Bar = foobar<Bar>();
And here is the equivalent operation in 'pure javascript':
var someBar = new bar();
function foobar() {
return someBar;
}
var myBar = foobar();
You can observe that my goal is straightforward - aiming for polymorphic type verification without the need for downcasting.