Skip to content

Unable to use custom Promise definition with two generic parameters as return value for async function #12973

Closed
@NoelAbrahams

Description

@NoelAbrahams

TypeScript Version: 2.1.4

Code

tsconfig.json

{
  "compilerOptions": {
    "target": "ES5",
    "module": "none",
    "noLib": true
  },
  "compileOnSave": true
}

Minimal Custom lib.d.ts

interface Object { }
interface IArguments { }
interface Function { }
interface String { }
interface Boolean { }
interface Number { }
interface Date { }
interface Array<T> { }
interface Error { }
interface RegExp { }
interface JSON { }

interface PromiseLike<T, TError> {

    then(
        onfulfilled?: ((value: T) => T | PromiseLike<T, TError>) | undefined | null,
        onrejected?: ((reason: TError) => T | PromiseLike<T, TError>) | undefined | null): PromiseLike<T, TError>;
}

interface Promise<T, TError> {

    then(onfulfilled?: ((value: T) => T | PromiseLike<T, TError>) | undefined | null, onrejected?: ((reason: TError) => T | PromiseLike<T, TError>) | undefined | null): Promise<T, TError>;
}

interface PromiseConstructor {

    readonly prototype: Promise<any, any>;

    new <T, TError>(executor: (resolve: (value?: T | PromiseLike<T, Error>) => void, reject: (reason?: any) => void) => void): Promise<T, Error>;

    reject<T>(reason: any): Promise<T, Error>;

    resolve<T>(value: T | PromiseLike<T, Error>): Promise<T, Error>;

    resolve(): Promise<void, Error>;
}

declare var Promise: PromiseConstructor;
declare type PromiseConstructorLike = new <T, TError>(executor: (resolve: (value?: T | PromiseLike<T, TError>) => void, reject: (reason?: any) => void) => void) => PromiseLike<T, TError>;

Sample Code

class Foo {


    public async foo() : Promise<number, Error> {

        return 10;
    }

    public async bar() {

        const val = await this.foo();

        return val;
    }
}

Expected behavior:

No compilation errors

Actual behavior:

The compiler prints the following errors:

error TS1057: Build:An async function or method must have a valid awaitable return type.
error TS2697: Build:An async function or method must return a 'Promise'. Make sure you have a declaration for 'Promise' or include 'ES2015' in your `--lib` option.
error TS1058: Build:Operand for 'await' does not have a valid callable 'then' member.
error TS2317: Build:Global type 'PromiseLike' must have 1 type parameter(s).
error TS2317: Build:Global type 'Promise' must have 1 type parameter(s).

I would like the rule Global type 'Promise' must have 1 type parameter(s) to be relaxed if possible.

Thanks!

Related issues:
#7588
#5413
#12737
#12292

Activity

mhegazy

mhegazy commented on Dec 16, 2016

@mhegazy
Contributor

I would not recommend changing the global Promise type. the compiler makes assumptions about how it is defined. same goes for PromiseLike.

if you want to use a different Promise definition, and you are running under --t es5, consider adding an explicit type annotation on you async functions with the promise type you are using, e.g.:

async function foo (a) : MyPromise<string, number, undefined> {
   .....
}
added
Working as IntendedThe behavior described is the intended behavior; this is not a bug
on Dec 16, 2016
NoelAbrahams

NoelAbrahams commented on Dec 16, 2016

@NoelAbrahams
Author

@mhegazy,

the compiler makes assumptions about how it is defined. same goes for PromiseLike.

The suggestion is to relax this assumption. There is no actual change to the runtime behaviour of Promise; the only change is that the errors are strongly typed. I don't really see why the compiler should enforce this restriction.

Also, in MyPromise<string, number, undefined> how do I ensure the error is strongly typed?

benjamingr

benjamingr commented on Dec 16, 2016

@benjamingr

This is a matter of checked vs. unchecked exceptions. You can get around this by subclassing Promise.

It's there for the same reason exceptions in regular non-promise functions aren't declared. It would make no sense to enforce this for async functions but not regular ones:

    public async foo() : number throws TypeError { // <- we don't do that in TS

        return 10;
    }

Checked exceptions have traditionally been very unpopular in languages that sport them (Java).

NoelAbrahams

NoelAbrahams commented on Dec 16, 2016

@NoelAbrahams
Author

You can get around this by subclassing Promise.

how?

gcnew

gcnew commented on Dec 16, 2016

@gcnew
Contributor

Checked exceptions have traditionally been very unpopular in languages that sport them (Java).

I don't think so.

benjamingr

benjamingr commented on Dec 16, 2016

@benjamingr

@gcnew I'd like to retract that statement. Mainly because I don't have anything objective to back it up and I don't think it's the debate we should be having anyway.

@NoelAbrahams class YourPromise<T,E> extends Promise<T> and overload the signature of the static reject, and then.

NoelAbrahams

NoelAbrahams commented on Dec 16, 2016

@NoelAbrahams
Author

That was something I thought would work, but the way Promise is defined in lib.d.ts it's not trivial.
(Also #12737 is a blocker, but that's not important.)

The original issue was not really about errors: it was to relax the restrictions on how Promise is defined in lib.d.ts. The fact that I'm using the second generic parameter as an error type is beside the point.

zpdDG4gta8XKpMCd

zpdDG4gta8XKpMCd commented on Dec 16, 2016

@zpdDG4gta8XKpMCd

#12737 is fixed it says

zpdDG4gta8XKpMCd

zpdDG4gta8XKpMCd commented on Dec 16, 2016

@zpdDG4gta8XKpMCd

related: #10751

locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @zpdDG4gta8XKpMCd@NoelAbrahams@benjamingr@gcnew@mhegazy

        Issue actions

          Unable to use custom Promise definition with two generic parameters as return value for async function · Issue #12973 · microsoft/TypeScript