Skip to content

Wrong return type inference in a generic function using Promise.all  #37664

Description

Can I resolve this problem below without the awaited keyword? how can I infer return type without having to use as unknown as R[] and providing a hardcoded type each time?

    // Promise.all(this.fork) take a T1[] where T1 is a Promise<number>
    // and return a Promise<T2[]> where T2 is a number
    // therefore T1 and T2 are not both «T»

TypeScript Version: 3.9.0-dev.20200326

Search Terms:
Promise.all
promise.all generic
generic awaited
awaied

Code

class MyMaybeList<T = any>, le 2020-03-24 à 03 45 35 EST

Code as text below -- Click to enlarge image -- #Pop N' Lock Theme by Luxcium ✨

export class MyMaybeList<T = any> {
  private constructor(values: T[]) {
    this.values = values;
  }

  private values: T[];

  // get =======================================================-| fork() |-====

  public get fork(): T[] {
    return this.values != null ? this.values.slice() : [].slice();
  }

  // public =====================================================-| map() |-====

  public map<R = any>(
    fn: (val: T, index: number, array: T[]) => R
  ): MyMaybeList<R> {
    return MyMaybeList.of(...this.values.map(fn));
  }

  // static ======================================================-| of() |-====

  public static of<TVal>(...val: TVal[]): MyMaybeList<TVal> {
    if (val == null || !val.length) return new MyMaybeList<TVal>([]);
    return new MyMaybeList<TVal>([...val]);
  }

  // async =====================================================-| will() |-====

  public async will /* <R> */() /* : Promise<MyMaybeList<R>> */ {
    // Promise.all(this.fork) take a T1[] where T1 is Promise<number>
    // and return a Promise<T2[]> where T2 is a number
    // therefore T1 and T2 are not both «T»
    console.log(this.fork);

    const willThen = Promise.all(this.fork);

    const thenWill = await willThen;
    return MyMaybeList.of(...thenWill);
  }
}

Example, le 2020-03-24 à 03 46 09 EST

Code as text below -- Click to enlarge image -- #Pop N' Lock Theme by Luxcium ✨

const oneToTen = MyMaybeList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
const powersOneToTen = oneToTen.map(async val => val * val);

// "log->" powersOneToTen: MyMaybeList<Promise<number>>
console.log(powersOneToTen);

// "log->" awaitedList: MyMaybeList<Promise<number>>
// instead of a -> MyMaybeList { Promise<number> }
// in fact is a -> Promise {  MyMaybeList<number> }
const awaitedPowersOneToTen = powersOneToTen.will /* <unnknow> */();
awaitedPowersOneToTen.then(awaitedList => console.log(awaitedList));

// Promise { <pending> } will resolve into ->
console.log(awaitedPowersOneToTen);

Console logs le 2020-03-24 à 03 46 58 EST

Click to enlarge image -- #Pop N' Lock Theme by Luxcium ✨

Now that #37610 has reverted the awaited type I don't know what to do I have provided an example above but my real-life situation is as follow :

I was relying on this solution because I have a Promise<MaybeList<Promise<ISymbolSearchResult[]>>>
where MaybeList is an array abstraction so I am using promise.all to remove the inner Promise I don't know what to do now to avoid using «as unknown as MaybeList<ISymbolSearchResult[]>» inside of my async function (which should be returning the Promise<MaybeList<ISymbolSearchResult[]>> instead of the Promise<MaybeList<Promise<ISymbolSearchResult[]>>>) *Note that I have an array of ISymbolSearchResult inside an arrayLike of type MaybeList so, in this case, an array inside of an array

Actual behavior:
Promise<MyMaybeList<Promise<number>>> (as in 3.9.0-dev.20200326)

Expected behavior:
Promise<MyMaybeList<number>> (as in 3.9.0-dev.20200324)

Related Issues:
#37610, #37526, #33055, #30551, #35998, #37534, #37115, #34925
maybe also:
#9998, #33707, #36232, #35136, #33562, #34883, #31394
as discussed in TypeScript 3.9 Iteration Plan #37198

Activity

  1. changed the title [-]Can not get correct return type inference when using Promise.all in a generic function[/-] [+]Wrong return type inference in a generic function when using Promise.all [/+] on Mar 28, 2020
  2. changed the title [-]Wrong return type inference in a generic function when using Promise.all [/-] [+]Wrong return type inference in a generic function using Promise.all [/+] on Mar 28, 2020
  3. adrienboulle commented on Apr 8, 2020

    @adrienboulle

    If it can help i have this example

    Here the thing that break type inferring is the fact that one of the promises has unknown type even if its return value is not used

  4. Luxcium commented on Apr 9, 2020

    @Luxcium
    Author

    If it can help i have this example

    Here the thing that breaks type inferring is the fact that one of the promises has unknown type even if its return value is not used

    **I am sorry Adrien Boullé (@adrienboulle) I am not sure what I should be looking for in your example you mention I think the line 13 where getNumbersB() is not used but I don't see the problem ... **

    Capture d’écran, le 2020-04-08 à 22 52 45

    click to enlarge image -- #Pop N' Lock Theme by Luxcium ✨

    At this moment I am still using 3.9.0-dev.20200324 because for some random reason I had that problem on 03-23 got that fix by chance on the 24th and it got reverted the day after ...

  5. Luxcium commented on Apr 9, 2020

    @Luxcium
    Author

    ok (OOPS!) I forgot to install the typescript@latest (3.8.3) and I think the typescript@next is not breaking (3.9.0-dev.20200408) so I can upgrade from 3.9.0-dev.20200324

    Capture d’écran, le 2020-04-08 à 23 01 50

    click to enlarge image -- #Pop N' Lock Theme by Luxcium ✨

    yes I have « 🍒» inside of my error messages LoL 😹

  6. adrienboulle commented on Apr 9, 2020

    @adrienboulle

    haha i can't blame you tu add some joy on your code!
    So if i understand correctly, 3.9.0 fixes the issue ?

  7. RyanCavanaugh commented on Apr 20, 2020

    @RyanCavanaugh
    Member

    I'm not really sure what's going on here; we need a concise problem description to work from

  8. Luxcium commented on Apr 21, 2020

    @Luxcium
    Author
  9. Luxcium commented on Apr 21, 2020

    @Luxcium
    Author

    The TypeScript playground site was not working correctly for me when I have first opened this issue it is now working ...

    With: 3.9.0-dev.20200324 the following code awaitedPowersOneToTen.then(awaitedList => console.log(awaitedList)); when I mouse over awaitedList it is a MyMaybeList<number>

    But with: 3.9.0-dev.20200420 the following code awaitedPowersOneToTen.then(awaitedList => console.log(awaitedList)); when I mouse over awaitedList it is a MyMaybeList<Promise<number>>

  10. Luxcium commented on Apr 21, 2020

    @Luxcium
    Author

    I am using Promise.all on something like an array or a list (MyMaybeList) and I want to infer the type without explicitly passing it (in a generic) ... Promise.all should remove the Promise inside of my list so I can get MyMaybeList<number> a list of "numbers" instead of gettingMyMaybeList<Promise<number>> a list of "Promises of a number" which is the type that I have before using Promise.all

  11. Luxcium commented on May 4, 2020

    @Luxcium
    Author

    I got this error message and don't know what I should do ...
    error(TS2345): Argument of type 'awaited T' is not assignable to parameter of type 'T'.
    'T' could be instantiated with an arbitrary type which could be unrelated to 'awaited T'.

    Capture d’écran, le 2020-05-04 à 17 38 39

    Code as text below -- Click to enlarge image -- #Pop N' Lock Theme by Luxcium ✨

    TypeScript code: lib/functional/promise-or-not.ts

    // ... [more code]
    
    export async function thenified<T>(
      promise: Promise<T>,
      funct: <R>(t: T) => R,
    ): Promise<any> {
      return promise.then(
        t => funct(t)
      );
    }

    Output: tsc Version 3.9.0-dev.20200324

    % ❯  tsc # 3.9.0-dev.20200324 
    lib/functional/promise-or-not.ts:10:16 - error TS2345: Argument of type 'awaited T' is not assignable to parameter of type 'T'.
      'T' could be instantiated with an arbitrary type which could be unrelated to 'awaited T'.
    
    10     t => funct(t)
                      ~
    Found 1 error.

    Also on Stack Overflow: Argument of type 'awaited T' is not assignable to parameter of type 'T'

    Playground 3.9.0-dev.20200324

    Playground Nightly

    Playground 3.8.3

  12. Luxcium commented on May 4, 2020

    @Luxcium
    Author

    Due to different other problems in my code when using other TS version I am stuck using Version 3.9.0-dev.20200324

    In regard to the problem described above in my previous comment I could, meanwhile, do:

    return promise.then(t => funct((t as any) as T));

    or do:

    return promise.then(t => funct((t as unknown) as T));

    I am not sure the difference between using unknown or any in this particular example ...


    This is when using Version 4.0.0-dev.20200504 other parts of code are not shown here, the problem is detailed above in this current GitHub issue #37664

    Many more problems using current version

  13. jakebailey commented on Jan 24, 2022

    @jakebailey
    Member

    After 4.5, I don't think that this is a problem anymore thanks to the Awaited changes; I'm going to close this, but can reopen if I'm mistaken.

  14. Luxcium commented on Jan 28, 2022

    @Luxcium
    Author

    It's not a problem anymore indeed !!! thanks to the TS Team to have made it possible... and sorry for the long delay but at least it is now resolved for me !!!

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

    Needs More InfoThe issue still hasn't been fully clarified

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions