Reputation: 4705
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?
Upvotes: 6
Views: 2214
Reputation: 4705
All fair if you don't want to use Promise.reject
and Promise.resolve
, but if you do - here's the easy fix.
Get rid of the | void
in the signature, and change the rejection returned to return Promise.reject<ISomething>(err);
. Works!
Here's the modified version from the question:
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 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<ISomething>(err);
}
}
Upvotes: 0
Reputation: 1113
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
Upvotes: 1