Share to Mastodon
While converting this website to Next.js from Gatsby, I had to translate my approaches from the latter to the former. Specifically, how to render individual components on the server. As Gatsby sites are static by default, this was not something I thought much about. Working with Next.js and TypeScript had me scratching my head on this issue. I couldn't figure out how to render async components in TypeScript without being met with the following error:
TS2786: 'SomeAsyncComponent' cannot be used as a JSX component. Its return type
'Promise<ReactElement<any, string | JSXElementConstructor<any>>>' is not a valid
JSX element. Type 'Promise<ReactElement<any, string | JSXElementConstructor<any>>>'
is missing the following properties from type 'ReactElement<any, any>': type, props, key
Without being able to leverage async components, I was forced to do async processing/rendering on the
client with use()
or useEffect()
hooks. This was not an ideal solution, and it also has some
limitations. For instance, if I wanted to call an external API inside a component, I would run into
CORS issues, unless I had access to the API server,
at least to the capacity where I could add a setting to allow the domain of my application.
Frustrated with this state of affairs, I did a search on how to use async components in a Next.js application. This search didn't return any useful results. From what I could see, using async components was supposed to 'just work', but I couldn't understand why it didn't work for me. That was until I discovered this GitHub issue, specifically, this comment.
To summarize, it appears that the TypeScript compiler does not yet have support for async JSX components. This is why I was unable to even build my application, rather than just experiencing error output in the client. The following directive placed above the async component solves this problem.
{/* @ts-expect-error Server Component */}
<MyAsyncComponent />
@ts-expect-error
alone will suffice, but adding the Server Component
comment adds helpful context as
to why an error is expected. When TypeScript eventually supports async JSX components (or if this is
accomplished via a Next.js plugin), the @ts-expect-error
directive will throw an error due to no error
being thrown by the component. You can then remove these directives and freely use async JSX components
in your code.