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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:15:01