React+TypeScript使用React.cloneElement传参类型缺失报错如何解决?
报错原因
TypeScript 只能检测你显性在JSX上传入的属性,你通过React.cloneElement动态注入的addClasses、renewTitle属性,TS无法感知,所以会认为你给Status、Bdays组件传参时缺少必填属性。
解决方案
方案1:子组件注入属性标记为可选(最简便)
直接把子组件接口中需要动态注入的属性设为可选即可,你能确定Block组件一定会注入这些属性,所以运行时不会出现未定义的情况:
interface IStatus { class: string, // 加?标记为可选属性 renewTitle?: (title: string) => void } interface IBDays { class: string, // 加?标记为可选属性 addClasses?: (classes: string[]) => void }
如果不想每次调用都判断属性是否存在,可以调用时加非空断言:
// Status组件内 props.renewTitle!("newTitle") // Bdays组件内 props.addClasses!([newClass])
方案2:泛型约束Block组件(更严谨)
如果需要更严格的类型校验,可以给Block组件加泛型,明确子组件可接收的注入属性:
interface IBlockInjectedProps { addClasses: (classes: string[] | ((prev: string[]) => string[])) => void renewTitle: (title: string | ((prev: string) => string)) => void } interface IBlock<T = {}> { children: React.ReactElement<T>, id: string, title: string } function Block<T extends Partial<IBlockInjectedProps>>(props: IBlock<T>) { // 内部逻辑不变 }
额外逻辑修复
你当前代码修改title不会生效,因为h2渲染的是传入的props.title,不是state里的title,修改Block组件的渲染代码:
function Block(props: IBlock) { const [classes, addClasses] = useState<string[]>([""]) const [title, renewTitle] = useState<string>(props.title) return ( <div id={props.id} className={classes.join(" ")}> {/* 把props.title改成state里的title */} <h2>{title}</h2> {React.cloneElement(props.children, {addClasses, renewTitle})} </div> ) }
如果需要追加类名而不是覆盖原有类名,可以修改addClasses的调用方式为函数式更新:
// Bdays组件内 props.addClasses!(prev => [...prev, newClass])
内容的提问来源于stack exchange,提问作者PoZuTPoH
相关产品推荐
相关产品推荐

