I want to make a typed async function with proper error handling.
I can define one like this:
export async function doSomething(userId:string) : Promise<ISomething | void> {
let somthing: ISomething = {};
try {
something.user = await UserDocument.findById(userId);
something.pet = await PetDocument.findOne({ownerId:userId});
return Promise.resolve(something);
} catch (err){
console.log("I would do some stuff here but I also want to have the caller get the error.");
return Promise.reject(err);
}
}
...which seems to work, but (for reasons that are clear), if I try to assign the result to an ISomething
object, I get the error Type 'void | ISomething' is not assignable to type 'ISomething'
.
let iSomething:ISomething;
iSomething = await doSomething('12'); //this give me the error
I get why that is. My question is, what pattern should I use for error handling in a case like this? Note that if the return type is Promise<IProfile>
instead then I get an error for the return Promise.reject(err);
line (which would return Profile<void>
).
In place of the line return Promise.reject(err);
I can use throw err;
, but there may be times where I'd want to use the Promise.reject
pattern (like if I want to do some more things before I return).
I have a feeling that I'm missing something with promises / async, but I can't find typed examples that follow this pattern.
...note that if I use the full Promise pattern it works fine:
doSomething('12')
.then( (something) => {//do stuff})
.catch( (err) => {//handle error});
Should I just be using throw
and forget about Promise.reject
? If I use throw
, will the .catch()
be triggered appropriately?
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
Error handlingA try/catch block can be used to handle asynchronous errors in an async function. Alluding to the fact that an async function always return a Promise, one can opt to use a . catch() in place of a whole try/catch block.
The await keyword before a promise makes JavaScript wait until that promise settles, and then: If it's an error, an exception is generated — same as if throw error were called at that very place. Otherwise, it returns the result.
Here's an example: new Promise((resolve, reject) => { resolve("ok"); }). then((result) => { throw new Error("Whoops!"); // rejects the promise }). catch(alert); // Error: Whoops!
Not returning a promise in the first place is how I usually implement the async await pattern:
export async function doSomething(userId:string) : Promise<ISomething>{
let something: ISomething = {};
try {
something.user = await UserDocument.findById(userId);
something.pet = await PetDocument.findOne({ownerId:userId});
return something;
} catch (err){
console.log("I would do some stuff here but I also want to have the caller get the error.");
throw(err);
}
}
so if you don't have to do intermediate cleanup you could strip it down to:
export async function doSomething(userId:string) : Promise<ISomething>{
let something: ISomething = {};
something.user = await UserDocument.findById(userId);
something.pet = await PetDocument.findOne({ownerId:userId});
return something;
}
and have
the subsequent awaited function catch the exception or
the calling function handle the rejected promise
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