You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
typeSomeNode=string|Promise<string>asyncfunctionrenderChild(): Promise<SomeNode>{returnPromise.resolve("test")}functionrenderApp(children: SomeNode){}// Should typecheck but errors:// Type 'Promise<string>' is not assignable to type 'string'.(2345)renderApp(renderChild())// ^?
π Actual behavior
Argument of type'Promise<SomeNode>' is not assignable to parameter of type'SomeNode'.
Type 'Promise<SomeNode>' is not assignable to type'Promise<string>'.
Type 'SomeNode' is not assignable to type'string'.
Type 'Promise<string>' is not assignable to type'string'.(2345)
input.tsx(13, 11): Did you forget to use 'await'?
π Expected behavior
No typechecking error
Additional information about the issue
Nodes in React are typed as type Node = AwaitedNodes | Promise<AwaitedNodes>. However, the return type of async Components is Promise<Node>. But TypeScript will not consider this a Component because Promise<Node> is not assignable to Node even though it should be since at runtime Promise<Promise<T>> will never be observable and always collapse to Promise<T>.
Users can either fix this by using an unwieldy Promise<Awaited<ReactNode>>.
We can also fix this at the type level by allowing Node | Promise<Node> as the return type. Though I suspect this just pushes the issue one Promise-wrapping level away when TypeScript could collapse wrapped Promises automatically.
We can also fix this at the type level by allowing Node | Promise<Node> as the return type.
I think this is probably what I'd recommend. I believe @rbuckton did explore something where Promise<T> could be compatible with T | Promise<T>; but I don't know if it would have handled the more recursive case you have up there.
You can't actually have a Promise<Promise<T>> in JS, but we have no mechanism to recursively unwrap a type parameter on instantiation. I looked into this a few years ago in #37615 (and #37540), but that solution depended on introducing magic inference rules for Promise-likes that couldn't be applied generally to other types.
π Search Terms
return type promise union
π Version & Regression Information
This is the behavior in every version I tried, and I reviewed the FAQ for entries about Promise
β― Playground Link
https://www.typescriptlang.org/play/?#code/C4TwDgpgBAyg9gWwgOTgE2gXigZ2AJwEsA7AcygB8oAFfRQnCAHjyLID4BYAKB4EMcIYgGMoAMwCuI4ITjEo+CMQz4AwgAtCAGzQAKAJQAuGnQQNm8JKgzsoAbx5QnCiMAn55teowB0inHBaAG4QugBEwBB4Yfo8AL48PJLSsvKKyhD4AIJgYLrCmjrpxpYo6BD69oncCbzcAPT1sOpwEjpQoJAFEMIA1lAARhLAUJl0+DiGPI1OACrg0ADkXmaMLAQkpOyLUAxQxHAjAjiEpMR8A1rQwHAdC1CLrJuLProATADMACwArLHc6RUOTygMyGm0en0-xmzlhAD0APw8IA
π» Code
π Actual behavior
π Expected behavior
No typechecking error
Additional information about the issue
Nodes in React are typed as
type Node = AwaitedNodes | Promise<AwaitedNodes>
. However, the return type of async Components isPromise<Node>
. But TypeScript will not consider this a Component becausePromise<Node>
is not assignable toNode
even though it should be since at runtimePromise<Promise<T>>
will never be observable and always collapse toPromise<T>
.Users can either fix this by using an unwieldy
Promise<Awaited<ReactNode>>
.We can also fix this at the type level by allowing
Node | Promise<Node>
as the return type. Though I suspect this just pushes the issue one Promise-wrapping level away when TypeScript could collapse wrapped Promises automatically.Original issue: vercel/next.js#67365
The text was updated successfully, but these errors were encountered: