Promise return type error after TypeScript upgrade

2019-07-01 20:18发布

问题:

Using typescript v2.3.4, the following code worked fine:

    getStuff() : Promise<IStuff>{

        return this.http.get(url, options)
            .toPromise()
            .then( (res) => {
                let stuff: IStuff;
                if (res.json().data){
                    stuff = res.json().data;
                }
                return stuff;
            })
            .catch( (reason) => {
                this.handleError(reason);
            });
    }

...where handleError is like this:

handleError = (error:any) => {
    this.debug(error);
    throw error;
}; 

Now, with typescript v2.4.1 I get the error: 'Type 'Promise<void | IStuff>' is not assignable to type 'Promise<IStuff>'. Type 'void | IStuff' is not assignable to type 'IStuff'. Type 'void' is not assignable to type 'IStuff'.'

I can see why that would be the case.

...but this DOES work, and it makes no sense to me that it would work when the other code does not:

getStuff() : Promise<IStuff>{

    return this.http.get(url, options)
        .toPromise()
        .then( (res) => {
            let stuff: IStuff;
            if (res.json().data){
                stuff = res.json().data;
            }
            return stuff;
        })
        .catch( (reason) => {
                if( reason.status) {
                    return Promise.reject(reason);
                } else {
                    this.handleError(reason);
                }
        });
}

...in the else case, it is doing exactly what the code above that generates the error is doing, and yet there's no error.

I can fix the problem by just changing handleError to be:

handleError = (error:any):Promise<any> => {
    this.debug(error);
    Promise.reject(error);
};

...but I'm curious what the specific change was that caused this to become an error, and why does adding the if/else block work correctly when it has an else path that is identical to the original code?

回答1:

With the TypeScript 2.4 release, TypeScript has become stricter with generics and Promise callbacks, which will cause issues with upgrades, especially those that use Promises. I've noticed this in several of my apps. You can read about it in the release notes for 2.4.