6

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?

3
  • ...I've answered part of my question: "If I use throw will the .catch() be triggered appropriately?" - yes, writing some test code shows it does. I guess thrown errors are turned into rejected promises in async functions. I'd still love to know how to use Promise.reject in this kind of situation though (specifically my problems around the typing errors). Commented Jan 25, 2017 at 23:29
  • The point is that you can use throw. Please use throw as what you have is a very confusing mix of patterns. Commented Jan 26, 2017 at 8:19
  • 1
    I don't agree it is a mix of patterns - having to use throw along with returning a promise seems more like a mix of patterns. Using Promise.resolve and Promise.reject seems like a consistent use of patterns. Commented Jan 26, 2017 at 16:14

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

Comments

0

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);
    }
}

1 Comment

This is a lie to the compiler, as Promise.reject is not returning something of type ISomething.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.