React组件用forwardRef遇TypeScript 2590复杂联合类型错误求助
解决React动态标签组件的TypeScript ts(2590)错误
问题根源
你的组件中DangerousHTMLProps的tag属性定义为T | ValidTags,加上泛型T本身是ValidTags的子类型,导致TypeScript需要处理一个包含所有HTML元素ref类型的超大联合类型,超出了编译器的处理上限,触发Expression produces a union type that is too complex to represent.ts(2590)错误。另外,ref的类型被简单定义为object,没有和动态标签对应的元素类型关联,也是类型推导混乱的原因。
修复方案
以下是修改后的代码,通过精准约束泛型和ref类型解决问题:
/** * This component is responsible for adding the innerHtml in the html element using dangerouslySetInnerHTML with html sanitization. */ import React, { HTMLAttributes, forwardRef, memo } from 'react'; import { isObjectEmpty, isStrEmpty, sanitizeHtml } from './helpers'; import withErrorBoundary from './withErrorBoundary'; // All valid HTML tags like 'div' | 'form' | 'a' | ... type ValidTags = keyof React.JSX.IntrinsicElements; // 获取标签对应的元素类型 type ElementForTag<T extends ValidTags> = React.JSX.IntrinsicElements[T]['ref'] extends React.Ref<infer E> ? E : never; // Generic type to generate HTML props based on its tag export type DangerousHTMLProps<T extends ValidTags> = { tag?: T; // 移除多余的ValidTags联合,泛型已约束T属于ValidTags htmlString: string; sanitizeProps?: object; } & HTMLAttributes<ElementForTag<T>>; // 关联标签对应的元素属性类型 const defaultTag = 'div' as const; function DangerousHTMLComponent<T extends ValidTags = typeof defaultTag>( { tag = defaultTag, htmlString, sanitizeProps = {}, ...rest }: DangerousHTMLProps<T>, ref: React.Ref<ElementForTag<T>> // 让ref类型和标签元素匹配 ): React.ReactElement { const ParentElem = tag as keyof React.JSX.IntrinsicElements; const sanitizePropsObj = isObjectEmpty(sanitizeProps) ? {} : sanitizeProps; if (isStrEmpty(htmlString)) { return <ParentElem {...rest} ref={ref} />; } return ( <ParentElem {...rest} ref={ref} dangerouslySetInnerHTML={{ __html: sanitizeHtml(htmlString, sanitizePropsObj) }} /> ); } const DangerousHTML = forwardRef(DangerousHTMLComponent); export default memo(DangerousHTML);
关键修改点
- 修正
tag的类型定义:把tag?: T | ValidTags改为tag?: T,因为泛型T已经被约束为ValidTags的子类型,不需要额外的联合类型,减少类型复杂度。 - 新增
ElementForTag类型:通过条件类型从标签的固有元素类型中提取对应的DOM元素类型,让ref和HTMLAttributes都能精准匹配当前标签的元素类型。 - 关联
ref的类型:将组件的第二个参数ref的类型改为React.Ref<ElementForTag<T>>,确保ref类型和动态标签的元素类型一致,避免模糊的object类型导致的推导混乱。 - 简化默认值处理:把
defaultTag标记为const,让TypeScript推导更精确;同时简化sanitizePropsObj的逻辑,避免不必要的类型断言。
这样修改后,TypeScript可以精准推导每个标签对应的元素和ref类型,不会再生成过于复杂的联合类型,解决ts(2590)错误的同时,也让组件的类型安全性更高。
内容的提问来源于stack exchange,提问作者Dhiraj sah
相关产品推荐
相关产品推荐

