| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
cc: Wesley Wigham (@weswigham), Daniel Rosenwasser (@DanielRosenwasser), Anders Hejlsberg (@ahejlsberg), Ryan Cavanaugh (@RyanCavanaugh) (since suggested reviewers weren't working) |
Sorry, something went wrong.
|
Wouldn't a more general operator, something like unwrap be of broader use ? I know of a couple of people trying to unwrap Array for example. Something like T unwrap G<infer> (with infer getting only one use). With the inheritance rules being tied to the variance of G. |
Sorry, something went wrong.
|
Looks like the position of type argument declarations is not the best for inserting modifiers. So if we use unwrap, it would be as follows: function f<T extends number>(x: unwrapped PrimiseLike<T>) {
} |
Sorry, something went wrong.
|
falsandtru (@falsandtru) I think there are complications in the syntax. For example what if you need to unwrap a type with more than one type parameter, you need to be able to specify the position of the argument that you are unwrapping by. |
Sorry, something went wrong.
|
If nested promises are allowed, then shouldn't the following be allowed? const expected: Promise<string> = undefined as Promise<Promise<string>>;
~~~~~~~~
!!! error TS2322: Type 'Promise<Promise<string>>' is not assignable to type 'Promise<string>'.What do you think of #35284 instead? |
Sorry, something went wrong.
Its not that simple, for several reasons:
All of these behaviors are already handled by await in the compiler today specifically for handling Promise-like types, and the awaited type operator is formalization of this behavior in the type system. This would not preclude us from introducing a separate mechanism for unrolling a recursive type in the future. |
Sorry, something went wrong.
We already investigated adding an Awaited<T> to the core library and abandoned that approach. The problem being that we cannot currently model the recursive unwrap of the await operator with a type alias. The only way that could be remotely feasible is if we had a mechanism to forbid Promise<Promise<T>>, but such a mechanism also does not yet exist. |
Sorry, something went wrong.
|
Is it necessary for Awaited<T> to be recursive, if the only way to get a nested promise is to explicitly write it as such, which is out of scope? Why make it recursive if Promise<Promise<T>> will someday be forbidden? |
Sorry, something went wrong.
|
I can't help but feel as though we're jumping too quickly to a syntactic solution here... From what I understand of this issue, we could hypothetically solve this problem without new syntax if we had a "canonized" story around recursive conditional types. Is that a reasonable assessment? Anecdotally, I've seen the topic of recursive types come up a lot, and I know there are a good few libraries available that implement various forms of the hack Ron Buckton (@rbuckton) mentioned. It definitely feels to me as though there's need for a more general feature (or set of features) in the recursive type space. Has there been any exploration/ideation into that space that would address this specific issue as part of a more general solution? :) |
Sorry, something went wrong.
I would argue that two years isn't "jumping too quickly". Adding awaited T doesn't preclude us from investigating recursive conditional types. The problem with a recursive type alias is the "halting problem": Adding that level of complexity can make the type system unpredictable as it can quickly become impossible to be able to reason over whether a type can be instantiated in finite time or using finite memory. Any solution for recursive type aliases would need to be very restrictive. |
Sorry, something went wrong.
That wasn't what was out of scope. What I was calling out was that writing Promise<Promise<number>> wouldn't be automatically replaced by Promise<number> by the compiler. |
Sorry, something went wrong.
|
I agree, awaited is not smart but inevitable. Since it is difficult to generalize unwrapping, we have to specify the kind of unwrapping like awaited. |
Sorry, something went wrong.
This is true. 🙂
Oh 100%. I don't mean to trivialise recursive types, as I'm very aware of the headaches they bring. 🙂 But people are writing them already (myself included), and there are libraries full of them. If we could build out that feature space a bit, then it's possible we wouldn't need special awaited syntax in the first place (which is why I brought it up). |
Sorry, something went wrong.
|
What are the cases where a non-recursive solution isn't equivalent? Why are those cases important? Do they justify adding a new kind of type? |
Sorry, something went wrong.
|
Ron Buckton (@rbuckton) Can’t it just be await <type>? |
Sorry, something went wrong.
|
My argument is that
It's clear why #21613 was investigated and rejected, if a recursive solution was assumed. What I'm searching for and haven't found yet, is why a non-recursive solution was rejected? |
Sorry, something went wrong.
|
I’d prefer if the type operator was just await T, as it’d make sense to me that the result of an await expression would be await <type>, rather than awaited <type>. |
Sorry, something went wrong.
|
Jack Bates (@jablko): The problem of Promise<Promise<T>> isn't just the fact you can explicitly write such a type, but that it's relatively easy to accidentally end up with such a type when composing higher-order functions. |
Sorry, something went wrong.
|
To me, await is more of an imperative operation. The word await is an action verb: it happens once and happens immediately. However, the result of an await is something that was awaited. The word awaited is a past participle and can be used as an adjective. If the thing you awaited was generic, then we must defer the resolution of the actual type until such time as it is fully instantiated. As a result, you can carry around an awaited T type for a value long after the actual await has occurred. |
Sorry, something went wrong.
|
I agree. So I agreed with awaited. |
Sorry, something went wrong.
...
This will result in an error as we haven't changed inference here. T is still inferred as Promise<number>, so your return type in the conditional is instantiated as Promise<Promise<number> extends number ? true : false> which becomes Promise<false>. However, if you change your example in this way: declare function f<T>(x: Promise<T>): Promise<awaited T extends number ? true : false>;
const expected: Promise<true> = f(undefined as any as Promise<Promise<number>>);Then you get the correct result. |
Sorry, something went wrong.
|
Daniel Rosenwasser (@DanielRosenwasser) in the DT test I'm seeing a lot of this from JQuery: ../jquery/misc.d.ts(1205,15): error TS2430: Interface 'PromiseBase<TR, TJ, TN, UR, UJ, UN, VR, VJ, VN, SR, SJ, SN>' incorrectly extends interface '_Promise<TR>'.
Types of property 'then' are incompatible.
Type '{ <ARD = never, AJD = never, AND = never, BRD = never, BJD = never, BND = never, CRD = never, CJD = never, CND = never, RRD = never, RJD = never, RND = never, ARF = never, AJF = never, ANF = never, BRF = never, BJF = never, BNF = never, CRF = never, CJF = never, CNF = never, RRF = never, RJF = never, RNF = never, AR...' is not assignable to type '<TResult1 = TR, TResult2 = never>(onfulfilled?: ((value: TR) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => _Promise<...>'.I'm investigating whether this is something I can fix in this PR or if I will just need to make a change to JQuery. |
Sorry, something went wrong.
|
Upon investigation, I think the fix will need to be in the JQuery types, due to the fact they are extending from both PromiseLike and copy of Promise. |
Sorry, something went wrong.
Would it make sense to accommodate Promise<Promise<number>> in this context and if so, what would be the differences between awaited T and type Awaited<T> = Promise<T> extends Promise<infer U> ? U : never;Assuming U would become awaited T? |
Sorry, something went wrong.
Currently, no. We're not doing anything special for conditionals here, and as I mentioned the problem would be easily addressable by using awaited T in your example.
I'm not sure what the difference would be, and I don't see how we could choose to assume the U in Promise<infer U> should be awaited T. |
Sorry, something went wrong.
|
There are some known breaks on DT that I am planning to address in parallel. |
Sorry, something went wrong.
|
To close multiple issues or PRs, you need to write the keyword before each of them: https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword |
Sorry, something went wrong.
|
ExE Boss (@ExE-Boss) thanks, I went ahead and closed them manually. |
Sorry, something went wrong.
Summary: Add the new keyword "awaited": microsoft/TypeScript#35998 Reviewers: #framework_syntax_highlighting, dhaumann, cullmann Reviewed By: #framework_syntax_highlighting, cullmann Subscribers: kwrite-devel, kde-frameworks-devel Tags: #kate, #frameworks Differential Revision: https://phabricator.kde.org/D28814
| Back | FazBrowse Home | New Git URL |
It has been over two years since we decided not to move forward with #17077 due to the advent of conditional types, however in that time we have still been unable to devise a reliable mechanism for defining a recursive conditional type that can properly handle the type-side of ECMAScript's await and native Promise unwrapping behavior.
Solutions like Awaited<T> were untenable given that the only way to make the conditional type "recursive" was to introduce complex type like the following:
T extends PromiseLike<infer U> ? { 0: Awaited<U> }[U extends any ? 0 : never ] : ...However, there are a number of problems with this approach:
As a result, I would like to reintroduce the awaited type operator from #17077 to meet our needs for a mechanism to recursively unwrap a Promise-like type for methods like Promise.all, Promise.race, Promise.allSettled, Promise.prototype.then, and Promise.prototype.catch. The awaited type operator has the following semantics:
This will help us to merge PRs such as #33707 without needing to introduce a non-recursive or pseudo-recursive Awaited<T> type.
Fixes: #27711, #31722
Closes: #36435, #36368.