如何为条件式Anchor/Button组件正确定义React.forwardRef类型?
React 条件组件的 Ref 类型适配方案
你的问题核心是联合类型的 Props 和 forwardRef 的泛型无法自动匹配对应关系:当as为"a"时,React期望接收Ref<HTMLAnchorElement>类型,但你传递的是ForwardedRef<HTMLAnchorElement | HTMLButtonElement>,TypeScript无法确认当前场景下ref的具体类型,因此报错。
最优解决方案:泛型关联组件类型与 Ref
通过泛型将as属性的值和对应的元素类型绑定,让TypeScript能精准推断ref的类型:
import React, { forwardRef, createElement } from 'react'; type TriggerElementType = "button" | "a"; // 基于as的值,推导对应的Props类型 type TriggerProps<T extends TriggerElementType> = T extends "button" ? React.ButtonHTMLAttributes<HTMLButtonElement> & { as: T } : React.AnchorHTMLAttributes<HTMLAnchorElement> & { as: T }; // 泛型组件,关联as类型与ref类型 const Trigger = forwardRef(function <T extends TriggerElementType>( { as, ...props }: TriggerProps<T>, ref: React.ForwardedRef< T extends "button" ? HTMLButtonElement : HTMLAnchorElement > ) { return createElement(as, { ...props, ref } as React.HTMLAttributes< T extends "button" ? HTMLButtonElement : HTMLAnchorElement >); });
简化方案:类型断言(不推荐,牺牲类型安全)
如果不想重构为泛型组件,也可以通过类型断言绕过TypeScript的检查,但会失去部分类型安全性:
import React, { forwardRef, createElement } from 'react'; type ConditionalProps = | ({ as: "button"; } & React.ButtonHTMLAttributes<HTMLButtonElement>) | ({ as: "a"; } & React.AnchorHTMLAttributes<HTMLAnchorElement>); const Trigger = forwardRef< HTMLAnchorElement | HTMLButtonElement, ConditionalProps >(function Trigger({ as, ...props }, ref) { return createElement(as, { ...props, // 断言ref为当前元素支持的类型 ref: ref as React.Ref<HTMLAnchorElement | HTMLButtonElement> }); });
为什么泛型方案更好?
泛型方案能让TypeScript在编译阶段就确保as的类型、Props的属性、ref的类型完全匹配,避免后续使用组件时出现类型错误;而类型断言只是强制关闭了TypeScript的检查,无法保证类型一致性。
内容的提问来源于stack exchange,提问作者wongx
相关产品推荐
相关产品推荐

