Skip to content

Type narrowing for awaited values #30551

Description

@samdenty

Search Terms

promise, type narrowing, await

Suggestion

The type narrowing that occurs inside if statements, should work with awaited values

Though generally speaking a type is used for values that are already

Examples

type A = {
  kind: 'a'
  a: string
}

type B = {
  kind: 'b'
  b: string
}

let data: A | B

async function valueTest() {
  if ((await data.kind) === 'a') {
    // 'data' hasn't been narrowed to type 'A'
    data.a // Error
  }

  // Works fine without await
  if (data.kind === 'a') {
    data.a // Okay
  }
}

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Activity

  1. MartinJohns commented on Mar 23, 2019

    @MartinJohns
    Contributor

    This is due to #9998.

  2. DanielRosenwasser commented on Mar 25, 2019

    @DanielRosenwasser
    Member

    I think it's more that there's a limited set of syntactic constructs we can analyze because it would be inefficient otherwise. I guess the thing I want to know is whether there's a reason to write code like that.

  3. jeremymeng commented on Jun 17, 2019

    @jeremymeng
    Member

    I guess this is the same issue that for-await-of doesn't narrow types?

    /// <reference lib="esnext.asynciterable"/>
    
    interface MyIterator<T> {
      next(): Promise<
        | {
            done: false;
            value: T;
          }
        | {
            done: true;
            value: undefined;
          }
      >;
      [Symbol.asyncIterator](): MyIterator<T>;
    }
    interface Item { name: string }
    
    async function m(iter: MyIterator<Item>) {
      for await (const it of iter) {
        console.log(it.name);           // Error here complaining about 'it': Object is possibly 'undefined'.ts(2532)
    
      }
    }
  4. jeremymeng commented on Jun 18, 2019

    @jeremymeng
    Member

    hmm, actually it is not related to await. iterator has the same error

    interface MyIterator<T> {
        next():
          | {
              done: false;
              value: T;
            }
          | {
              done: true;
              value: undefined;
            }
        ;
        [Symbol.iterator](): MyIterator<T>;
    }
    
    interface Item { name: string }
    
    function m(iter: MyIterator<Item>) {
        for (const it of iter) {
            console.log(it.name);           // Error here complaining about 'it': Object is possibly 'undefined'.ts(2532)
    
        }
    }
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

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions