'React 18 Fragment complaining of too many children

A few days ago I tried to add Storybook to my React app, and basically everything imploded. I restored from a backup, but it didn't include the node_modules folder, and 'npm install' did not return things to the way they were. Now I getting this error from Typescript on Fragments:

ERROR in src/components/customTable/customTableHeader.tsx:83:12

TS2746: This JSX tag's 'children' prop expects a single child of type 'ReactNode', but multiple children were provided.
    81 |           title={title}
    82 |         >
  > 83 |           <Fragment>
       |            ^^^^^^^^
    84 |             {label}
    85 |             {renderSortIcon(column)}
    86 |           </Fragment>
  • npm = 6.14.7
  • node = 14.7.0

package.json

{
  "name": "web-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@fortawesome/fontawesome-free": "^5.15.4",
    "@fortawesome/fontawesome-svg-core": "^1.2.36",
    "@fortawesome/free-solid-svg-icons": "^5.15.4",
    "@fortawesome/react-fontawesome": "^0.1.15",
    "@reduxjs/toolkit": "^1.8.1",
    "@sentry/react": "^6.13.0",
    "@sentry/tracing": "^6.13.0",
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "@tinymce/tinymce-react": "^3.13.0",
    "axios": "^0.21.4",
    "bootstrap": "^5.1.1",
    "hoist-non-react-statics": "^3.3.2",
    "joi": "^17.6.0",
    "jquery": "^3.6.0",
    "lodash": "^4.17.21",
    "match-sorter": "^6.3.1",
    "moment": "^2.29.3",
    "react": "^18.1.0",
    "react-bootstrap": "^2.0.0-beta.6",
    "react-bootstrap-typeahead": "^5.2.2",
    "react-data-grid": "^7.0.0-beta.12",
    "react-dnd": "^16.0.1",
    "react-dnd-html5-backend": "^16.0.1",
    "react-dom": "^18.1.0",
    "react-dropzone": "^11.4.2",
    "react-helmet-async": "^1.2.3",
    "react-modal": "^3.15.1",
    "react-redux": "^7.2.4",
    "react-router": "^6.3.0",
    "react-router-dom": "^6.3.0",
    "react-scripts": "^5.0.1",
    "react-toastify": "^8.2.0",
    "redux": "^4.1.1",
    "redux-thunk": "^2.3.0",
    "reselect": "^4.1.5",
    "socket.io": "^4.1.3",
    "socket.io-client": "^4.1.3",
    "web-vitals": "^1.1.2",
    "webpack": "^5.72.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@babel/core": "^7.15.0",
    "@babel/plugin-transform-runtime": "^7.15.0",
    "@babel/preset-env": "^7.15.0",
    "@types/axios": "^0.14.0",
    "@types/bootstrap": "^5.1.4",
    "@types/jest": "^26.0.24",
    "@types/joi": "^17.2.3",
    "@types/jquery": "^3.5.6",
    "@types/lodash": "^4.14.172",
    "@types/react-bootstrap-typeahead": "^5.1.8",
    "@types/react-dom": "^18.0.0",
    "@types/react-helmet": "^6.1.5",
    "@types/react-modal": "^3.12.1",
    "@types/react-pdf": "^5.0.9",
    "@types/react-toastify": "^4.1.0",
    "@types/socket.io": "^3.0.2",
    "axios-mock-adapter": "^1.19.0",
    "babel-jest": "^26.6.3",
    "ts-loader": "^9.2.5",
    "typescript": "^4.6.3"
  }
}

tsconfig.json

{
  "extends": "../tsconfig-base.json",
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "declaration": true,
    "declarationMap": true,
    "jsx": "react-jsx",
    "sourceMap": true,
    // "outDir": "./lib",
    "baseUrl": "./",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.json",
    "src/**/*.sql",
    "html/**/*.html",
    "src/stories/providerWrapper.tss",
    "src/components/item/relationCard.tss"
  ],
  "exclude": ["node_modules", "dest", "test", "lib"]
}


Solution 1:[1]

I fixed by annotating anything that returns non-jsx elements as returning ReactNode

error scenario

function GuiltyComponent(){ return React.createPortal(...,...) }
<React.Fragment><GuiltyComponent/></React.Fragment>

function InnocentComponent(): React.ReactNode { return React.createPortal(...,...) as any }
<React.Fragment><InnocentComponent/></React.Fragment>

Solution 2:[2]

I think the error message is misleading. At least it was for me.

I assume the return type of renderSortIcon is not assignable to ReactNode (e.g. possibly void, unknown, ...). That, in combination with having multiple children, will trigger the error.

To fix it, make sure the return value is correct. For example if you have some check like if (!hasSortIcon()) return;, return null instead.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 gobien
Solution 2 schummar