Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'SomeComponent' cannot be used as a JSX component. #42292

Closed
1 task done
professorhaseeb opened this issue Nov 1, 2022 · 108 comments
Closed
1 task done

'SomeComponent' cannot be used as a JSX component. #42292

professorhaseeb opened this issue Nov 1, 2022 · 108 comments
Labels
area: app App directory (appDir: true) linear: next Confirmed issue that is tracked by the Next.js team. locked Upstream Related to using Next.js with a third-party dependency. (e.g., React, UI/icon libraries, etc.).

Comments

@professorhaseeb
Copy link

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

    Operating System:
      Platform: win32
      Arch: x64
      Version: Windows 10 Pro
    Binaries:
      Node: 18.12.0
      npm: N/A
      Yarn: N/A
      pnpm: N/A
    Relevant packages:
      next: 13.0.1-canary.4
      eslint-config-next: 13.0.0
      react: 18.2.0
      react-dom: 18.2.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

Any components are producing IDE error but builds successfully.

'SomeComponent' cannot be used as a JSX component.
  Its return type 'Promise<Element>' is not a valid JSX element.
    Type 'Promise<Element>' is missing the following properties from type 'ReactElement<any, any>': type, props, key `ts(2786)`

Expected Behavior

probably not give an error when using async components

Link to reproduction

no link

To Reproduce

// ~/component/SomeComponent.tsx

export default async function SomeComponent() {
    let categories: any = await getCategories()
    return ...
}
@professorhaseeb professorhaseeb added the bug Issue was opened via the bug report template. label Nov 1, 2022
@icyJoseph
Copy link
Contributor

I think a fix is upcoming, but pretty much the issue is that TypeScript doesn't understand async components... It always expects JSX as child, not Promise<JSX>.

Many are type casting the component and exporting that type casted version... I think it might be better to do:

import { RSCList } from "../../../components/RSCList";

export default function Page({ params }: { params: { id: string } }) {
  return (
    <div>
      Order: {params.id}
      <div>
        {/* @ts-expect-error Server Component */}
        <RSCList />
      </div>
    </div>
  );
}

When the types are fixed, the @ts-expect-error directive will complain that it is unused...

This fix might come from the next typescript plugin I think, not sure.

@professorhaseeb
Copy link
Author

@icyJoseph

{/* @ts-expect-error Server Component */} worked for now.

Thanks

@shuding shuding assigned shuding and unassigned shuding Nov 2, 2022
@saidMounaim
Copy link

Thanks @icyJoseph

{/* @ts-expect-error Server Component */} worked for me

@timneutkens timneutkens added Upstream Related to using Next.js with a third-party dependency. (e.g., React, UI/icon libraries, etc.). area: app App directory (appDir: true) kind: bug and removed bug Issue was opened via the bug report template. labels Nov 5, 2022
@timneutkens
Copy link
Member

This particular error is hardcoded in TypeScript. The React team is working with the TypeScript team to resolve this. For now you can use the recommendation above 👍

@leerob
Copy link
Member

leerob commented Nov 5, 2022

Just added a few notes about this workaround to the beta docs as well, thank you!

@diegohaz
Copy link

The React team is working with the TypeScript team to resolve this.

Is there a public issue/PR on the TypeScript repo where that work can be followed?

@is-it-ayush
Copy link

The {/* @ts-expect-error Server Component */} get's rid of the typescript error as mentioned by icyJoseph. However, This produces a different Server Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.. Unsure If I'm doing something wrong. I'm using a RSC in the /pages directory which is Promise<JSX.Element> and returns a list. The data to it is passed via gssp and props.

My guess is that the Promise is not resolved at the time of rendering. Hence, the error. If this is so, any workarounds until it is fixed.

@dantman
Copy link

dantman commented Jan 6, 2023

However, This produces a different Server Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.. Unsure If I'm doing something wrong. I'm using a RSC in the /pages directory which is Promise<JSX.Element> and returns a list. The data to it is passed via gssp and props.

To my understanding server components are only available in the new app/ folder not pages/ so that would be the cause of your issue.

@is-it-ayush
Copy link

However, This produces a different Server Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.. Unsure If I'm doing something wrong. I'm using a RSC in the /pages directory which is Promise<JSX.Element> and returns a list. The data to it is passed via gssp and props.

To my understanding server components are only available in the new app/ folder not pages/ so that would be the cause of your issue.

Ah Yes. I was not aware of it. In a sandbox I was able to reproduce the above error which I was expecting in /pages directory. Then I switched to beta /app directory and it worked charmingly. I now understand why it happened. Thanks @dantman!

@bongdungyeuem27
Copy link

You only use async component inside app folder and server component.

@gaithoben
Copy link

The issue may have been introduced to your project via some other packages' peer dependency.

If you have a .tsconfig file, Add following to compilerOptions:

"paths": {
"react": [ "./node_modules/@types/react" ]
}

@Kamrulhasan12345
Copy link

Don't know why, but I am using app directory, but I can still see, Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead. issue while rendering

@mstachalski
Copy link

Same here, I am passing a SSC as a child to a CSC. Both are wrapped in a SSC as mentioned in the Nextjs Docs.
Still I am getting the error "TS2786: 'TopicCardContent' cannot be used as a JSX component."

<TopicCard side={"left"}><TopicCardContent /></TopicCard>

@bgdnvk
Copy link

bgdnvk commented Feb 9, 2023

I'm using NextJS 13, the error still persists if you pass async server components. But {/* @ts-expect-error Server Component */} makes it work, would love to have a non-hacky way to approach this.

@Kamrulhasan12345
Copy link

@bgdnvk Mine is a render-time error, so this doesn't get mine working.

@sjohns21
Copy link

I upgraded my package types:
"@types/node": "18.14.2",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
and it was resolved!

@roniaxe
Copy link

roniaxe commented Feb 28, 2023

I upgraded my package types: "@types/node": "18.14.2", "@types/react": "18.0.28", "@types/react-dom": "18.0.11", and it was resolved!

Didn't work for me.

@sooohka
Copy link

sooohka commented Mar 2, 2023

I upgraded my package types: "@types/node": "18.14.2", "@types/react": "18.0.28", "@types/react-dom": "18.0.11", and it was resolved!

didn't work either :(

@AveshLutchman
Copy link

I upgraded my package types: "@types/node": "18.14.2", "@types/react": "18.0.28", "@types/react-dom": "18.0.11", and it was resolved!

Didn't work for me, on most recent for each as well.

@BurgerZ
Copy link

BurgerZ commented Mar 10, 2023

I'm on Next.js 13 and I've found two workarounds:

First one is using a const:

async function Page() {
    const asyncComponent: JSX.Element = await AsyncComponent({ props: any })
    return (
        <Suspense fallback={<>Loading...</>}>
            ......
            {asyncComponent}
            ......
        </Suspense>
    )
}

Second one is using {/* @ts-expect-error Server Component */}:

async function Page() {
    return (
        <Suspense fallback={<>Loading...</>}>
            ......
            {/* @ts-expect-error Server Component */}
            <AsyncComponent />
            ......
        </Suspense>
    )
}

glennreyes added a commit to glennreyes/glennreyes.com that referenced this issue Mar 11, 2023
@hiendaovinh
Copy link

The problem with {/* @ts-expect-error Server Component */} is that it will silence other typing errors.

@sami616
Copy link

sami616 commented Mar 20, 2023

@hiendaovinh

Here is a wonky workaround which gets around the issue without losing all type safety for your incoming props. 👇🏼

type UserPostsProps = {
  userId: number
}

async function UserPosts({ userId }: UserPostsProps) {
  const userPosts: any = await fetch(
    `https://jsonplaceholder.typicode.com/posts?userId=${userId}`
  ).then(res => res.json())

  return (
    <ul>
      {userPosts.map((post: any) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// As a temporary work around, we can override the type so that it returns a JSX.Element instead of a Promise 
const _UserPosts = UserPosts as unknown as (props: UserPostsProps) => JSX.Element
export { _UserPosts as UserPosts }

@lucgagan
Copy link
Contributor

lucgagan commented Jun 7, 2023

Didn't expect this to work, but nuking node_modules and pnpm-lock.yarn and re-installing actually fixed the issue.

@qmmr
Copy link

qmmr commented Jun 9, 2023

In my case that was enough 💪

diff --git a/package.json b/package.json
index b5f95bd..c53ca79 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
-    "@types/react": "18.2.7",
+    "@types/react": "18.2.9",
     "@types/react-dom": "18.2.4",
@@ -33,7 +33,7 @@
-    "typescript": "^5.0.4"
+    "typescript": "^5.1.3"
   },

@travistylervii
Copy link

Finally worked:

  1. Updated packages.
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
"typescript": "^5.1.3"
  1. Nuked node_modules.
  2. Nuked package-lock.json
  3. Restarted Typescript & ESlist server.
  4. Sold my first born to the coding gods.
  5. Restarted VS Code.

No error. :')

@tomosnam
Copy link

This is what nextjs doc says: https://nextjs.org/docs/app/building-your-application/configuring/typescript)

@urakymzhan
Copy link

It worked with ts: 18 and react/types: 18
Thanks all

@wisteria-hill-technologies
Copy link

wisteria-hill-technologies commented Jun 13, 2023

Unfortunately, upgrading typescript solves the "cannot be used as a JSX component" error, but it will break eslint for me with eslint-config-next in next/core-web-vitals.
My IDE webstorm can no longer detect .eslintrc.json.
{
"extends": ["next/core-web-vitals"]
}

@fakhrads
Copy link

Finally worked:

  1. Updated packages.
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
"typescript": "^5.1.3"
  1. Nuked node_modules.
  2. Nuked package-lock.json
  3. Restarted Typescript & ESlist server.
  4. Sold my first born to the coding gods.
  5. Restarted VS Code.

No error. :')

This guide fixed my issue

@shubasishdas
Copy link

Finally worked:

  1. Updated packages.
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
"typescript": "^5.1.3"
  1. Nuked node_modules.
  2. Nuked package-lock.json
  3. Restarted Typescript & ESlist server.
  4. Sold my first born to the coding gods.
  5. Restarted VS Code.

No error. :')

This guide along with this link fixed my issue - https://nextjs.org/docs/app/building-your-application/configuring/typescript

@hydRAnger
Copy link
Contributor

hydRAnger commented Jun 23, 2023

I found this issue will occur again if upgrade to 😕

    "@types/react": "18.2.13",
    "@types/react-dom": "18.2.6",
    "typescript": "5.1.3"

but below works

   "@types/react": "18.2.12",
   "@types/react-dom": "18.2.5",
   "typescript": "5.1.3"

@fanzypantz
Copy link

I found this issue will occur again if upgrade to 😕

    "@types/react": "18.2.13",
    "@types/react-dom": "18.2.6",
    "typescript": "5.1.3"

but below works

   "@types/react": "18.2.12",
   "@types/react-dom": "18.2.5",
   "typescript": "5.1.3"

What react verrsion? I am on latest and still got errors from these versions.

@hydRAnger
Copy link
Contributor

I found this issue will occur again if upgrade to 😕

    "@types/react": "18.2.13",
    "@types/react-dom": "18.2.6",
    "typescript": "5.1.3"

but below works

   "@types/react": "18.2.12",
   "@types/react-dom": "18.2.5",
   "typescript": "5.1.3"

What react verrsion? I am on latest and still got errors from these versions.

    "react": "18.2.0",
    "react-dom": "18.2.0",

@noviceGuru
Copy link

For who wants to test an async Component :

In my opinion it makes sense for TypeScript to throw an error, after all this is an async function and may return a Promise. So, I would await it to return the JSX we are expecting:

test('RSCList  renders correctly', async () => {
	 render(
		await (async () => await RSCList())()
	 )

	expect(...).toBe(...)
})

@timneutkens
Copy link
Member

Based on https://twitter.com/sebsilbermann/status/1664356039876124672 I created a new Next.js application using create-next-app and was able to verify it works now.

  • pnpm create next-app --typescript typescript-async-component
  • Changed app/page.tsx:
async function MyComponent() {
  await new Promise((resolve) => {
    setTimeout(resolve, 500);
  });

  return <h1>Hello World</h1>;
}

And added:

<div className={styles.center}>
  <MyComponent />
</div>

Great work @eps1lon!

In my opinion it makes sense for TypeScript to throw an error, after all this is an async function and may return a Promise. So, I would await it to return the JSX we are expecting:

The latest version of React (specifically for server components) supports async functions as JSX, TypeScript just wasn't up to date with that yet.

@timneutkens timneutkens added linear: next Confirmed issue that is tracked by the Next.js team. and removed linear: next Confirmed issue that is tracked by the Next.js team. labels Jul 3, 2023
@stefanprobst
Copy link
Contributor

@timneutkens i am still seeing an error with an explicit Promise<ReactNode> return type annotation: "Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method.ts(1062)"

see #42292 (comment)

@pawelblaszczyk5
Copy link

pawelblaszczyk5 commented Jul 3, 2023

@timneutkens i am still seeing an error with an explicit Promise<ReactNode> return type annotation: "Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method.ts(1062)"

see #42292 (comment)

ReactNode now basically includes the Promise<ReactNode> part atm, so your type is recursive and never ends 😄 If you really want to explicitly type it - using just a ReactNode should be fine

@stefanprobst
Copy link
Contributor

stefanprobst commented Jul 3, 2023

ReactNode now basically includes the Promise part atm, so your type is recursive and never ends smile If you really want to explicitly type it - using just a ReactNode should be fine

hmm, async function SomeComponent(): ReactNode { /** */ } results in: "The return type of an async function or method must be the global Promise type. Did you mean to write 'Promise<string | number | boolean | ReactElement<any, string | JSXElementConstructor> | Iterable | ReactPortal | null | undefined>'? ts(1064)"

@pawelblaszczyk5
Copy link

ReactNode now basically includes the Promise part atm, so your type is recursive and never ends smile If you really want to explicitly type it - using just a ReactNode should be fine

hmm, async function SomeComponent(): ReactNode { /** */ } results in: "The return type of an async function or method must be the global Promise type. Did you mean to write 'Promise<string | number | boolean | ReactElement<any, string | JSXElementConstructor> | Iterable | ReactPortal | null | undefined>'? ts(1064)"

Oh, that's strange, I've checked it now and I see this issue as well. Maybe it's because the underlying type is using PromiseLike instead of native Promise interface 🤔 Because it seems like it gets stripped in proposed type

image

I personally don't use explicit return types so I don't have an idea for a good solution here, sorry. Though, it's not related to this issue tbh, it's just a typing problem

@eps1lon
Copy link
Member

eps1lon commented Jul 3, 2023

Promise<React.ReactNode> seems to work just fine with latest types: Playground Link

The only bug we need to fix in types/react is that async is only for experimental when it's already available in canary.

@jacobsfletch
Copy link
Contributor

Bumping @types/react to v18.2.14 fixed this for me in dev, but for some reason its still throwing an error when building 🤷

Screenshot 2023-07-06 at 12 34 02 AM

Screenshot 2023-07-06 at 12 32 38 AM

I also tried explicitly typing the return of my component to Promise<React.ReactNode> like @stefanprobst suggested but that is throwing the same error for me as was reported. For now I get around this by using @ts-expect-error but ts thinks this directive is unused:

Screenshot 2023-07-06 at 12 55 49 AM

@jjm2317
Copy link
Contributor

jjm2317 commented Jul 6, 2023

If you are using the jsxImportSource option in tsconfig.json, there is a possibility that the issue you encountered could be due to the outdated version of the related jsx parsing module.

In my case, I was using the "jsxImportSource": "@emotion/react" option in tsconfig.json. When I updated @types/react from version 18.0 to 18.2.14, I faced the problem 'Component' cannot be used as a JSX component. I found that this issue was fixed in the release version 11.11.1 of @emotion/react, as mentioned in https://github.com/emotion-js/emotion/releases/tag/%40emotion%2Freact%4011.11.1. After updating @emotion/react to the latest version, the problem was resolved.

@karlhorky
Copy link
Contributor

karlhorky commented Jul 6, 2023

More background on the @emotion/react problem (fixed in @emotion/[email protected]):

@ghost
Copy link

ghost commented Jul 7, 2023

Bumping @types/react to v18.2.14 fixed this for me in dev, but for some reason its still throwing an error when building 🤷

Screenshot 2023-07-06 at 12 34 02 AM

Screenshot 2023-07-06 at 12 32 38 AM

I also tried explicitly typing the return of my component to Promise<React.ReactNode> like @stefanprobst suggested but that is throwing the same error for me as was reported. For now I get around this by using @ts-expect-error but ts thinks this directive is unused:

Screenshot 2023-07-06 at 12 55 49 AM

@jacobsfletch
Make sure your devDependencies are updated. I noticed mine weren't on my Nextjs package in my monorepo

image

@WooodHead
Copy link

WooodHead commented Jul 8, 2023

I solved this problem with following steps (if you are using VSCode):

Source: https://stackoverflow.com/a/65151679/3317931

image

Latest Typescript version has fixed this error.
image

@github-actions
Copy link
Contributor

github-actions bot commented Aug 7, 2023

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot added the locked label Aug 7, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: app App directory (appDir: true) linear: next Confirmed issue that is tracked by the Next.js team. locked Upstream Related to using Next.js with a third-party dependency. (e.g., React, UI/icon libraries, etc.).
Projects
None yet
Development

No branches or pull requests