I'm implementing this button in my app.
In my button component I have:
@Input() callback: () => Promise<null>;
onClick() {
this.spinnerService.show();
this.callback().then(() => {
this.spinnerService.hide();
}, () => {
this.spinnerService.hide();
});
}
(I don't use async / await because the "tech lead" doesn't want me too)
The component template:
<my-button [callback]="doSomething">
</my-button>
Everything works fine when I pass this kind of code to the component's input:
doSomething = () => {
return myService.doSomething()
.toPromise()
.then((response) => console.log('promise resolved'));
}
But I need to break from this function earlier:
doSomething() {
if (condition) {
return;
}
return myService.doSomething()
.toPromise()
.then((response) => console.log('promise resolved'));
}
I get
ERROR TypeError: Cannot read property 'then' of undefined
I've tried forcing a promise with the same result
if (condition) {
return Promise.resolve(null);
// or
return new Promise((resolve) => { resolve(null); });
}
Empty-promise definition (idiomatic) A promise that is either not going to be carried out, worthless or meaningless.
Returns a new Promise object that is resolved with the given value. If the value is a thenable (i.e. has a then method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise, the returned promise will be fulfilled with the value.
The Promise.resolve() method "resolves" a given value to a Promise . If the value is a promise, that promise is returned; if the value is a thenable, Promise.resolve() will call the then() method with two callbacks it prepared; otherwise the returned promise will be fulfilled with the value.
For this input
@Input() callback: () => Promise<null>;
there is no guarantee that it's assigned to proper value. Additional check if callback
was specified should be added.
A safer way to manage this is to use async
functions in these places because they consistently use promises:
async onClick() {
this.spinnerService.show();
try {
if (this.callback)
await this.callback()
} finally {
this.spinnerService.hide();
}
}
doSomething
is supposed to return a promise unconditionally, and this can also be addressed with async
:
async doSomething() {
if (!condition)
return myService.doSomething().toPromise();
}
If async
functions can't be used for some reason (although there are no good ones, because they are spec-compliant, first-class citizens in TypeScript), promises should be consistently processed in functions (also helpful for testing). doSomething
isn't properly typed, and this allows improper function return. It should be:
onClick(): Promise<void> {
this.spinnerService.show();
return Promise.resolve(this.callback ? this.callback() : undefined)
.catch(() => {})
.then(() => {
this.spinnerService.hide();
});
}
and
doSomething(): Promise<void> {
if (condition) {
return Promise.resolve();
}
return myService.doSomething().toPromise();
}
And the type of callback
will be Promise<void>
, not Promise<null>
.
Regular (non-arrow) doSomething
method should be bound to this
in constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With