MUI中如何正确为ForwardedRef编写TypeScript类型
问题背景
你需要实现自定义转发ref的复选框组件,传入DataGrid作为基础复选框使用,当前实现中使用了as React.RefObject<HTMLButtonElement>类型断言绕开TypeScript检查,你希望找到更规范的实现方案,同时确认这类场景下类型断言是否属于可接受的写法。
现有实现代码
const CustomCheckbox = ({ checkboxRef, ...props }: { checkboxRef: React.ForwardedRef<unknown>; }) => ( <Checkbox {...props} ref={checkboxRef as React.RefObject<HTMLButtonElement>} sx={{ color: "#363636", "&.Mui-checked": { color: "#363636" } }} /> ); const ForwardCustomCheckbox = forwardRef((props, ref) => { return <CustomCheckbox {...props} checkboxRef={ref} />; }); <DataGrid ... components={{ BaseCheckbox: ForwardDarkCheckbox }} />
注:现有代码中ForwardDarkCheckbox属于笔误,实际应为定义的ForwardCustomCheckbox
最优实现方案
你当前代码需要写类型断言的核心原因,是没有给forwardRef传入正确的泛型参数,还额外加了一层把ref类型标记为unknown的中间组件,主动丢失了类型信息。完全可以去掉冗余的中间层,直接通过泛型约束实现全链路类型安全,不需要任何类型断言:
import { forwardRef } from 'react'; import { Checkbox, CheckboxProps } from '@mui/material'; // forwardRef泛型参数顺序:<ref指向的元素类型, 组件接收的props类型> const ForwardCustomCheckbox = forwardRef<HTMLButtonElement, CheckboxProps>((props, ref) => { return ( <Checkbox {...props} ref={ref} sx={{ color: "#363636", "&.Mui-checked": { color: "#363636" } }} /> ); }); // 传入DataGrid直接使用即可 <DataGrid // 其余业务属性 components={{ BaseCheckbox: ForwardCustomCheckbox }} />
如果确实需要拆分中间组件(比如要在复选框外层加额外的逻辑、样式封装),不要把中间组件接收的ref类型设为unknown,直接标注正确的类型即可,同样不需要断言:
import { forwardRef, ForwardedRef } from 'react'; import { Checkbox, CheckboxProps } from '@mui/material'; const CustomCheckbox = ({ checkboxRef, ...props }: CheckboxProps & { checkboxRef: ForwardedRef<HTMLButtonElement>; }) => ( <Checkbox {...props} ref={checkboxRef} sx={{ color: "#363636", "&.Mui-checked": { color: "#363636" } }} /> ); const ForwardCustomCheckbox = forwardRef<HTMLButtonElement, CheckboxProps>((props, ref) => { return <CustomCheckbox {...props} checkboxRef={ref} />; });
关于
as类型断言的使用边界 你抵触用as绕过类型检查的思路是正确的,日常开发中优先通过补全泛型、修正类型定义解决类型报错,是比直接断言更稳妥的做法。
这类类型断言仅在以下场景属于可接受的写法:
- 你100%确认值的运行时类型和断言类型一致,类型报错来自上游第三方库的类型定义缺陷,且短时间无法推动上游修复
- 断言的范围尽可能窄,不要直接大范围断言为
any/unknown,只针对确定类型的最小粒度值做断言 - 必要时补充单行注释说明断言原因,方便后续维护
你当前场景的类型报错完全来自自身代码的类型标注错误,不属于上游缺陷,因此没有使用类型断言的必要,直接按上述方案修正类型定义即可。
内容的提问来源于stack exchange,提问作者rjumatov
相关产品推荐
相关产品推荐

