在TypeScript中如何正确使用forwardRef?自定义组件props报错怎么解决?
解决方案
你遇到的报错核心原因是TypeScript无法自动推导forwardRef包裹组件的自定义Props类型,需要你主动声明类型定义,具体修改方案如下:
方案1:支持动态tag的完整写法
如果你的组件需要支持通过tag属性动态切换渲染标签,可以用泛型实现完整的类型适配:
步骤1:定义Props类型
import type { ComponentProps, ElementType, ReactNode } from 'react' interface AvatarProps<T extends ElementType = 'div'> { // 自定义属性,可根据业务调整可选值范围 color?: string size?: 'sm' | 'md' | 'lg' className?: string tag?: T children?: ReactNode // 继承tag对应元素的所有原生属性 } & ComponentProps<T>
步骤2:给forwardRef添加泛型声明
import { forwardRef } from 'react' import classnames from 'classnames' const Avatar = forwardRef(<T extends ElementType = 'div'>( props: AvatarProps<T>, ref: React.Ref<Element> ) => { const { color, className, size, tag: Tag = 'div', // tag默认值设为div ...rest } = props return ( <Tag className={classnames('avatar', { [className]: className, [`bg-${color}`]: color, [`avatar-${size}`]: size })} ref={ref} {...rest} > {/* 其余业务代码 */} </Tag> ) }) as <T extends ElementType = 'div'>(props: AvatarProps<T> & React.RefAttributes<Element>) => React.ReactElement export default Avatar
方案2:固定tag的简化写法
如果你的组件不需要动态切换渲染标签,默认固定为div,可以用更简洁的写法:
import { forwardRef, HTMLAttributes } from 'react' import classnames from 'classnames' // 直接声明Props,继承div原生属性 interface AvatarProps extends HTMLAttributes<HTMLDivElement> { color?: string size?: 'sm' | 'md' | 'lg' className?: string } // forwardRef两个泛型分别对应:ref指向的元素类型、组件Props类型 const Avatar = forwardRef<HTMLDivElement, AvatarProps>((props, ref) => { const { color, className, size, ...rest } = props return ( <div className={classnames('avatar', { [className]: className, [`bg-${color}`]: color, [`avatar-${size}`]: size })} ref={ref} {...rest} > {/* 其余业务代码 */} </div> ) }) export default Avatar
调用验证
修改完成后两种调用方式都不会再报类型错误:
// 普通调用 <Avatar size="sm" color="success" /> // 传ref调用 const ref = React.createRef<HTMLDivElement>(); <Avatar ref={ref} size="sm" color="success" />
内容的提问来源于stack exchange,提问作者tickwave
相关产品推荐
相关产品推荐

