Skip to content

awaited operator doesn't work with type guards #37512

Description

Ron Buckton (@rbuckton)

TypeScript Version: master

Search Terms:

Code

declare function isAwaited(value: any): value is awaited unknown;
function f<a>(a: a): void {
  isAwaited(a) && a;
}

Expected behavior:
The narrowed type of a is awaited a.
Actual behavior:
The narrowed type of a is a.

Playground Link:

Related Issues:

Activity

  1. falsandtru commented on Mar 23, 2020

    @falsandtru
    ContributorAuthor

    Probably we have to replace isPromiseLike with isAwaited.

              if (isPromiseLike(value)) {
                internal.status = {
                  state: State.resolved,
                  result: value,
                };
                value.then(
                  value => {
                    assert(internal.status.state === State.resolved);
                    internal.status = {
                      state: State.fulfilled,
                      result: value,
                    };
                    resume(internal);
                  },
                  reason => {
                    assert(internal.status.state === State.resolved);
                    internal.status = {
                      state: State.rejected,
                      result: reason,
                    };
                    resume(internal);
                  });
              }
              else {
                internal.status = {
                  state: State.fulfilled,
                  result: value!, // error
                };
                resume(internal);
              }
    Type 'NonNullable<T>' is not assignable to type 'awaited T'.
      Type 'T' is not assignable to type 'awaited T'.ts(2322)
    

    https://github.com/falsandtru/spica/blob/v0.0.343/src/promise.ts

  2. rbuckton commented on Mar 24, 2020

    @rbuckton
    Contributor

    The problem is that awaited unknown is just reduced to unknown, so you are asserting that value is unknown. The awaited type does work in type guards:

    image

    Playground link: https://www.typescriptlang.org/play/index.html?ts=3.9.0-dev.20200322#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXywGcBBAdyiwxGAB4AVAPgAoA3KCZEALnjvgB94UcpWq8AlDzYcERISKrBeAbgBQKdNjxJ6zAB48+g4RUUT4Ab1XwbBRPCZEyp6kz3jxl67Z961PgF9VAKA

  3. rbuckton commented on Mar 24, 2020

    @rbuckton
    Contributor

    Let me know if that addresses your concerns so that I can close this issue.

  4. falsandtru commented on Mar 24, 2020

    @falsandtru
    ContributorAuthor

    Basically type arguments are not used in type guards. Can you remove type arguments to accept all types? Actually, your function doesn't accept T | awaited T | PromiseLike<T>.

    Ideally, since T can be considered as thenable when T is not awaited T, isAwaited function should work as follows. Here isAwaited function proves or ensures that T is just a union of awaited T and PromiseLike<T>.

    declare function isAwaited(value: any): value is awaited any; // or awaited typeof value
    function f<T>(x: T | awaited T | PromiseLike<T>) {
        if (isAwaited(x)) {
            x; // awaited T
        }
        else {
            x; // PromiseLike<T>
        }
    }
  5. nmain commented on Mar 24, 2020

    @nmain

    Just to make sure I'm understanding this right, would this be a reasonable implementation of isAwaited? No matter what T is, awaited T is never PromiseLike ("thennable"), so value is awaited unknown just means that value is not PromiseLike.

    function isAwaited(value: any): value is awaited unknown {
        return !value || typeof value.then !== "function";
    }
  6. rbuckton commented on Mar 24, 2020

    @rbuckton
    Contributor

    awaited is only preserved when the type argument is generic, so awaited unknown is just unknown. Similar to awaited any is just any. It's only preserved at higher order.

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

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions