Skip to content

Can't infer T from awaited T #37526

Description

Looks like resolving this problem by type inference is difficult. We may need unawaited operator.

TypeScript Version: 3.9.0-dev.20200322

Search Terms:

Expected behavior:
pass
Actual behavior:

Argument of type 'T' is not assignable to parameter of type 'awaited T | PromiseLike<awaited T> | undefined'.
  Type 'T' is not assignable to type 'PromiseLike<awaited T>'.(2345)

Related Issues:

Code

function f<T>(a: T): Promise<awaited T> {
    return new Promise(r => r(a));
}
Output
"use strict";
function f(a) {
    return new Promise(r => r(a));
}
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": 2,
    "target": "ES2017",
    "jsx": "React",
    "module": "ESNext"
  }
}

Playground Link: Provided

Activity

  1. rbuckton commented on Mar 23, 2020

    @rbuckton
    Contributor

    We don't necessarily need an unawaited operator. Since Promise<T> is assignable to Promise<awaited T>, we can change inference to infer Promise<T> in this scenario.

  2. Luxcium commented on Mar 24, 2020

    @Luxcium

    Update

    My problem is solved with the nightly version of typescript but I will leave it there in case it can be useful for something or someone

    "typescript": "3.9.0-dev.20200324"

    I have placed a copy of this now fixed problem in #33055 and in #33707 hoping it can be helpful and not too spammy ...

    Issue now fixed

    I have a similar problem and I don't know if I should open a different issue ...

    "typescript": "3.8.3"

        // 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»

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

    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

    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

    /*
     // 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); will display same as console.log(powersOneToTen);
    
    
    
    // console.log(powersOneToTen); ->
    // "log->" powersOneToTen: MyMaybeList<Promise<number>>
    MyMaybeList {
      values: [
        Promise { 1 },
        Promise { 4 },
        Promise { 9 },
        Promise { 16 },
        Promise { 25 },
        Promise { 36 },
        Promise { 49 },
        Promise { 64 },
        Promise { 81 },
        Promise { 100 }
      ]
    }
    
    
    
    // console.log(awaitedPowersOneToTen); ->
    // "log ->" awaitedPowersOneToTen: Promise<MyMaybeList<Promise<number>>>
    Promise { <pending> }
    // Promise { <pending> } will resolve into ->
    
    // awaitedPowersOneToTen.then(awaitedList => console.log(awaitedList)); ->
    // console.log(awaitedList) ->
    // "log->" awaitedList: MyMaybeList<Promise<number>>
    // instead of a -> MyMaybeList { Promise<number> }
    // in fact is a (should be) -> Promise {  MyMaybeList<number> }
    MyMaybeList {
      values: [
         1,  4,  9, 16,  25,
        36, 49, 64, 81, 100
      ]
    }
    */
  3. Luxcium commented on Mar 27, 2020

    @Luxcium

    Now that #37610 has reverted the awaited type I don't know what to do I have posted 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[]>>>)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Needs InvestigationThis issue needs a team member to investigate its status.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions