Skip to content

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

Closed
@Luxcium

Description

@Luxcium

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

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