You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React第三方组件无法作为JSX组件使用的TS报错解决方案

React JSX组件类型不兼容报错(TS2786)修复方案

问题描述

当前项目基于 React 17.0.2 开发,集成 notistack@2.0.5 版本。引入 SnackbarProvider 组件编写如下代码时:

import { SnackbarProvider } from 'notistack';

return <SnackbarProvider maxSnack={3}>
  <AppRouter />
</SnackbarProvider>

抛出如下TypeScript错误:

'SnackbarProvider' cannot be used as a JSX component.
  Its instance type 'SnackbarProvider' is not a valid JSX element.
    The types returned by 'render()' are incompatible between these types.
      Type 'React.ReactNode' is not assignable to type 'import("/Users/madukadilshan/Desktop/projects/sma-web/node_modules/@sm/common-ui/node_modules/@types/react/index").ReactNode'.
        Type '{}' is not assignable to type 'ReactNode'.ts(2786)

引入 react-perfect-scrollbar 的 PerfectScrollbar 组件时,也出现完全相同的报错。

当前项目相关依赖版本:

  • react: 17.0.2
  • notistack: 2.0.5
  • react-perfect-scrollbar: ^1.5.8
  • 自定义公共组件包内置 react 版本: 17.0.2

该问题在安装自行开发的自定义组件包后首次出现,此前项目运行正常。最初公共UI包使用 React 18 版本,判断为React版本不一致导致,将公共包React版本降级到v17后重新安装,甚至删除node_modules目录重装所有依赖,报错仍然存在。

问题进展

将公共包React版本从v18调整为v17后,原有报错转移到公共UI包内依赖的其他第三方React组件上,问题未根治。已尝试的方案包括:

  1. 使用any类型做类型断言(非预期最终方案):
import { SnackbarProvider } from 'notistack';
const SnackbarProviderX: any = SnackbarProvider;

return <SnackbarProviderX></SnackbarProviderX>
  1. 升级主项目React版本到v18,匹配最初公共包的React v18版本,该操作修复了notistack的报错,但又引发@mui包的同类型报错,陷入修复一个问题又出现新同类型问题的循环。

根本原因

该类报错的核心原因是项目中存在多份互不兼容的@types/react类型定义。TypeScript不会跨目录合并同名类型包,当主项目、公共组件包、公共组件包依赖的第三方包各自安装了不同版本的@types/react(比如一份17.x、一份18.x)时,TS会判定不同来源的React.ReactNode、JSX元素实例类型不属于同一个类型,最终抛出TS2786错误。
单纯升级/降级React版本、删除node_modules重装无法解决问题,是因为包管理器默认会给未做正确依赖声明的包单独安装其依赖的@types/react版本,形成多版本嵌套。


正规修复方案

按优先级依次执行以下操作,可彻底解决该问题:

方案1:在公共组件包中正确声明React为peerDependency

修改自定义公共UI包的package.json,将react、react-dom移到peerDependencies中,版本号写兼容当前使用的React大版本的范围;@types/react、@types/react-dom仅保留在devDependencies中即可,例如:

{
  "peerDependencies": {
    "react": ">=17.0.0 <19.0.0",
    "react-dom": ">=17.0.0 <19.0.0"
  },
  "devDependencies": {
    "@types/react": "^17.0.2",
    "@types/react-dom": "^17.0.2"
  }
}

注意:绝对不要把@types/react放到dependencies中,否则安装公共包时会强制嵌套安装对应版本的类型包,直接引发多版本冲突。
该配置符合React组件包的开发规范,除了解决类型冲突,还能避免多份React副本导致的hooks调用报错。修改后重新发布公共包,主项目更新到最新版公共包后删除node_modules和锁文件(package-lock.json/yarn.lock/pnpm-lock.yaml)重新安装依赖即可。

方案2:通过包管理器强制统一全项目@types/react版本

如果暂时无法修改公共包配置,可以在主项目中通过配置强制所有依赖使用同一版本的@types/react,从根源消除多版本问题:

  • 若使用npm,在主项目package.json中添加overrides字段:
{
  "overrides": {
    "@types/react": "^17.0.2",
    "@types/react-dom": "^17.0.2"
  }
}
  • 若使用yarn,在主项目package.json中添加resolutions字段:
{
  "resolutions": {
    "@types/react": "^17.0.2",
    "@types/react-dom": "^17.0.2"
  }
}
  • 若使用pnpm,在主项目package.json中添加pnpm.overrides字段:
{
  "pnpm": {
    "overrides": {
      "@types/react": "^17.0.2",
      "@types/react-dom": "^17.0.2"
    }
  }
}

添加配置后删除node_modules和锁文件,重新执行依赖安装命令即可。该配置会强制项目中所有依赖包都使用主项目指定版本的@types/react,不会再出现嵌套安装多版本类型包的问题。

方案3:配置TypeScript类型解析路径(兜底方案)

如果上述方案仍未生效,可以在主项目的tsconfig.json中添加路径别名,强制所有@types/react的导入都指向主项目本地安装的类型包:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "react": ["./node_modules/@types/react"],
      "react-dom": ["./node_modules/@types/react-dom"]
    }
  }
}

配置完成后重启TS服务即可生效。


注意事项

  • 不要使用any类型断言临时规避问题,该操作会丢失所有组件的类型校验,后续出现属性传错、参数不匹配等问题无法被TS识别。
  • 不要在不同依赖中混用React 17和React 18的类型定义,只要全项目统一使用同一个大版本的@types/react,该类报错会完全消失。

内容的提问来源于stack exchange,提问作者Dilshan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:39:29