react-tiny-popover组件TSDX构建遇TS2786错误:Popover无法作JSX组件
解决TS2786错误:Popover无法作为JSX组件使用
问题场景
项目基于tsdx、rollup和storybook搭建,使用react-tiny-popover库开发Popover组件,storybook运行正常,但执行tsdx构建时抛出TS2786类型错误。
错误信息
(typescript) Error: my-new-project/src/components/Popover/PopoverComponent.tsx(5,12): semantic error TS2786: 'Popover' cannot be used as a JSX component.
Its return type 'ReactNode' is not a valid JSX element.
Type 'string' is not assignable to type 'Element'.
Error: my-new-project/src/components/Popover/PopoverComponent.tsx(5,12): semantic error TS2786: 'Popover' cannot be used as a JSX component.
Its return type 'ReactNode' is not a valid JSX element.
Type 'string' is not assignable to type 'Element'.
组件代码
Popover主组件
import React, { useState } from 'react'; import { PopoverComponent } from './PopoverComponent'; import { Paper } from '../Paper'; import type { ReactNode } from 'react'; export type PopoverPosition = 'top' | 'bottom' | 'left' | 'right'; export interface PopoverProps { label: ReactNode | string; children: ReactNode | string; className?: string; classNamePanel?: string; containerClassName?: string; positions?: PopoverPosition; isCloseClickElement?: boolean; } export const Popover: React.FC<PopoverProps> = ({ children, className = '', containerClassName = '', label, positions = 'bottom', isCloseClickElement, classNamePanel = '', }) => { const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false); return ( <div className={`food2c-popover ${className}`}> <PopoverComponent containerStyle={{ padding: '12px', }} positions={positions} isOpen={isPopoverOpen} reposition={false} onClickOutside={(e) => { e.stopPropagation(); setIsPopoverOpen(false); }} containerClassName={containerClassName} content={() => ( <div className={`food2c-popover-panel ${classNamePanel}`}> <Paper onClickPaper={() => isCloseClickElement ? setIsPopoverOpen(false) : null } > {children} </Paper> </div> )} > <button className="food2c-popover-button" onClick={(e) => { e.stopPropagation(); setIsPopoverOpen(!isPopoverOpen); }} > {label} </button> </PopoverComponent> </div> ); };
PopoverComponent封装
import React from 'react'; import { PopoverProps, Popover } from 'react-tiny-popover'; export const PopoverComponent: React.FC<PopoverProps> = props => { return (<Popover {...props}>{props.children}</Popover>) as JSX.Element; };
项目配置文件
rollup.config.js
import sass from 'rollup-plugin-sass'; import replace from '@rollup/plugin-replace'; export default { input: 'index.js', output: { file: 'dist/bundle.js', format: 'cjs', }, plugins: [ sass({ insert: true, output: 'dist/bundle.css', }), replace({ preventAssignment: true, }), ], };
tsdx.config.js
const postcss = require('rollup-plugin-postcss'); const autoprefixer = require('autoprefixer'); const cssnano = require('cssnano'); const svgr = require('@svgr/rollup'); module.exports = { rollup(config, options) { config.plugins.push( postcss({ plugins: [autoprefixer, cssnano], inject: false, extract: 'bundle.css', }), svgr() ); return config; }, };
tsconfig.json
{ // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs "include": ["src", "types"], "compilerOptions": { "module": "esnext", "lib": ["dom", "esnext"], "importHelpers": true, "declaration": false, "sourceMap": true, "rootDir": "./src", "strict": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true, "moduleResolution": "node", "jsx": "react", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "noEmit": false } }
解决方案
核心问题分析
错误根源在于:
PopoverComponent错误复用了react-tiny-popover的PopoverProps,该类型允许children为string,但React组件作为JSX使用时,返回值必须是合法JSX元素,string类型不符合要求。- 手动添加
as JSX.Element断言无法解决底层类型冲突,反而掩盖了类型不匹配的问题。
修复步骤
- 修正Props类型命名与匹配:将react-tiny-popover的
PopoverProps重命名导入,避免与自定义组件的Props混淆,确保PopoverComponent的Props完全匹配第三方库要求。 - 移除无效类型断言:react-tiny-popover的Popover组件本身返回合法JSX元素,无需手动断言。
- 可选:约束父组件输入类型:如果需要严格控制输入,可将
PopoverProps中的label和children限制为ReactElement类型,避免传入string。
修复后的PopoverComponent代码
import React from 'react'; import { PopoverProps as TinyPopoverProps, Popover as TinyPopover } from 'react-tiny-popover'; export const PopoverComponent: React.FC<TinyPopoverProps> = props => { return <TinyPopover {...props}>{props.children}</TinyPopover>; };
可选:严格约束父组件Props
export interface PopoverProps { label: React.ReactElement; children: React.ReactElement; className?: string; classNamePanel?: string; containerClassName?: string; positions?: PopoverPosition; isCloseClickElement?: boolean; }
验证修复
执行tsdx build命令,此时类型检查将通过,构建可正常完成。
内容的提问来源于stack exchange,提问作者William Gabriel
相关产品推荐
相关产品推荐

