React+TypeScript 子组件绑定prop函数到onClick报类型不兼容错误
问题背景
使用React + TypeScript开发自定义切换按钮组件时,将父组件传入的函数作为props传递给子组件,在子组件内将该函数绑定给原生div的onClick事件时抛出类型错误:
(property) React.DOMAttributes.onClick?: React.MouseEventHandler | undefined
Type '(checked: boolean) => void' is not assignable to type 'MouseEventHandler'.
Types of parameters 'checked' and 'event' are incompatible.
Type 'MouseEvent' is not assignable to type 'boolean'.ts(2322)
涉及的初始代码:
父组件App代码(src/App.tsx)
import React from 'react'; import ReactDOM from 'react-dom'; import Switch from './Switch'; interface State { buttonOn: boolean; } class App extends React.PureComponent<{}, State> { public state: State = { buttonOn: false, }; onChange = (checked: boolean) => this.setState({ buttonOn: checked }); render() { return ( <div> <Switch checked={this.state.buttonOn} onChange={(checked) => this.onChange(!checked)} /> </div> ); } } ReactDOM.render(<App />, document.getElementById('app')!);
子组件Switch代码(src/Switch/index.tsx)
import React from 'react'; import './index.css'; interface Props { checked: boolean; onChange: (checked: boolean) => void; disabled?: boolean; } export default class Switch extends React.PureComponent<Props> { render() { return ( <div> <div onClick={this.props.onChange} /> {/* 报错位置 */} </div> ); } }
错误原因
类型不匹配的核心是两种回调的函数签名完全不一致:
- 原生DOM元素的
onClick事件要求绑定的回调符合React.MouseEventHandler类型,事件触发时会自动传入*鼠标事件对象(MouseEvent)*作为第一个参数 - 自定义的
props.onChange约定入参为boolean类型的选中状态值,直接将其绑定给原生onClick时,TypeScript检测到参数类型无法对齐,因此抛出类型错误。
除此之外原代码还存在逻辑冗余问题:父组件和子组件如果都做状态取反,会导致最终状态翻转两次,切换功能失效。
修复方案
- 修改子组件的事件绑定逻辑,不要直接把props传入的回调绑给原生事件,新增一层适配函数:在原生点击事件触发时,手动计算最新的选中状态,再作为参数调用props.onChange。
修复后的Switch组件核心代码:export default class Switch extends React.PureComponent<Props> { render() { return ( <div> <div onClick={() => { // 点击时取反当前选中状态,将布尔值传给父组件回调 this.props.onChange(!this.props.checked) }} /> </div> ); } } - 移除父组件中重复的取反逻辑,因为子组件已经传入了更新后的正确布尔值,父组件直接同步状态即可:
修复后的App组件传参部分:<Switch checked={this.state.buttonOn} onChange={this.onChange} // 直接传入定义好的onChange方法即可,无需额外包装取反 />
扩展说明
如果后续需要在点击逻辑中操作原生事件对象(比如阻止冒泡、阻止默认行为),可以在适配函数中接收事件参数,处理完自定义逻辑后再调用props传入的回调:
<div onClick={(e) => { e.stopPropagation(); // 其他需要基于事件对象处理的逻辑 this.props.onChange(!this.props.checked) }} />
注意不要混淆自定义组件的props回调和原生DOM事件回调的类型定义:前者的参数完全由业务逻辑自定义,后者的参数是React内置的事件类型,二者不能直接互相赋值,必须通过中间适配层做参数转换。
内容的提问来源于stack exchange,提问作者wongwong3000
相关产品推荐
相关产品推荐

