Skip to content

Nested Promise not automatically unwrappedΒ #59111

Open
@eps1lon

Description

@eps1lon

πŸ”Ž 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

type SomeNode = string | Promise<string>

async function renderChild(): Promise<SomeNode> {
    return Promise.resolve("test")
}

function renderApp(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.

Original issue: vercel/next.js#67365

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions