TS/React嵌套使用forwardRef传递ref报TS2322错误如何修复
forwardRef嵌套传递ref时TypeScript类型报错修复
问题复现
在嵌套使用forwardRef封装的React组件时,内层组件接收外层透传的ref时抛出TS类型错误,复现代码如下:
const DEFAULT_ELEMENT = "button"; export type PropsOf<TTag = any> = TTag extends React.ElementType ? React.ComponentProps<TTag> : never; export type ButtonProps = PropsOf<typeof DEFAULT_ELEMENT> & {}; // 自定义Button组件,可独立正常运行: export const Button = forwardRef<HTMLButtonElement, ButtonProps>( (props, ref) => (<button ref={ref} {...props}/>) ) // 基于Button封装的IconButton组件,TypeScript对ref属性抛出类型错误: export const IconButton = forwardRef<HTMLButtonElement, ButtonProps>( (props, ref) => ( <Button ref={ref} // 此处TS抛出错误 {...props} /> ))
抛出的错误信息:
TS2322: Type 'string | ((instance: HTMLButtonElement | null) => void) | RefObject
| null' is not assignable to type 'Ref | undefined'.
Type 'string' is not assignable to type 'Ref| undefined'.
报错截图:
错误原因
- 你定义的
ButtonProps是直接提取原生button标签的属性类型,原生DOM元素的ref类型兼容旧版string类型ref,而forwardRef包装后的组件接收的ref类型Ref<HTMLButtonElement>不支持string类型ref,两者类型范围不匹配。 - 手动声明的
ButtonProps没有关联Button组件的实际ref类型,TS无法识别Button作为forwardRef组件的正确ref签名,透传时直接沿用了原生button的ref类型定义,导致校验失败。
修复方案
推荐使用类型工具自动提取组件的正确props类型(含ref),从根源解决类型不匹配问题:
const DEFAULT_ELEMENT = "button"; export type PropsOf<TTag = any> = TTag extends React.ElementType ? React.ComponentProps<TTag> : never; // 先定义基础Button组件 export const Button = forwardRef<HTMLButtonElement, PropsOf<typeof DEFAULT_ELEMENT>>( (props, ref) => (<button ref={ref} {...props}/>) ) // 使用ComponentPropsWithRef提取Button组件的完整合法props类型,自动推导正确的ref类型 export type ButtonProps = React.ComponentPropsWithRef<typeof Button>; // IconButton使用提取后的ButtonProps,ref传递不再报类型错误 export const IconButton = forwardRef<HTMLButtonElement, ButtonProps>( (props, ref) => ( <Button ref={ref} {...props} /> ))
如果只是临时修复,也可以在传递ref时做类型断言,但这种方式会丢失部分类型校验能力,不推荐长期使用:
export const IconButton = forwardRef<HTMLButtonElement, ButtonProps>( (props, ref) => ( <Button ref={ref as React.Ref<HTMLButtonElement>} {...props} /> ))
内容的提问来源于stack exchange,提问作者Spadar Shut
相关产品推荐
相关产品推荐

