如何为React插槽组件属性编写正确的TypeScript类型
React组件插槽属性的TypeScript类型优化方案
原始组件代码
interface MyComponentProps<T extends React.ElementType> { SlotComponent: T slotComponentProps: React.ComponentProps<T> } function MyComponent<T extends React.ElementType>({ SlotComponent, slotComponentProps, }: MyComponentProps<T>): React.ReactNode { return ( <div> <SlotComponent {...slotComponentProps} /> {/* Other things go here. */} </div> ) }
遇到的问题
- 尝试将
SlotComponent设为可选并默认值设为'button'时,出现TypeScript错误:TS2322: Type '"button"' is not assignable to type 'T'. '"button"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'ElementType<any, keyof IntrinsicElements>'. SlotComponent = 'button', ~~~~~~~~~~~~~ - 尝试将
slotComponentProps设为可选时,出现TypeScript错误:TS2322: Type '{}' is not assignable to type 'LibraryManagedAttributes<T, any>'. <SlotComponent {...slotComponentProps} /> ~~~~~~~~~~~~~ - 尝试将
slotComponentProps设为可选并添加{}作为默认值时,出现TypeScript错误:TS2322: Type '{}' is not assignable to type 'ComponentProps<T>'. slotComponentProps = {}, ~~~~~~~~~~~~~~~~~~
解决方案
通过调整泛型约束、设置泛型默认值,并结合React内置的属性映射逻辑,可解决所有类型报错问题,同时保证组件灵活性:
修改后的完整代码
import React from 'react'; interface MyComponentProps<T extends React.ElementType = 'button'> { SlotComponent?: T; slotComponentProps?: Partial<React.LibraryManagedAttributes<T, React.ComponentProps<T>>>; } function MyComponent<T extends React.ElementType = 'button'>({ SlotComponent = 'button' as T, slotComponentProps = {}, }: MyComponentProps<T>): React.ReactNode { return ( <div> <SlotComponent {...slotComponentProps} /> {/* Other things go here. */} </div> ); }
关键修改说明
- 泛型默认值处理:给泛型
T设置默认值'button',当用户不传入SlotComponent时,TypeScript会自动将T推断为'button'。同时用as T断言默认值类型,解决默认值与泛型的兼容性问题。 - 插槽属性类型兼容:使用
Partial<React.LibraryManagedAttributes<T, React.ComponentProps<T>>>作为slotComponentProps的类型,LibraryManagedAttributes会处理React内置的属性映射规则(比如className与class的转换),Partial让所有属性变为可选,确保空对象默认值能兼容所有组件的属性类型。 - 属性可选性配置:将
SlotComponent和slotComponentProps都标记为可选(?),满足灵活传参的需求。
验证场景
- 无参数调用:自动渲染button组件,无类型报错
<MyComponent /> - 传入自定义组件:
const CustomLink = ({ href, children }: { href: string; children: React.ReactNode }) => <a href={href}>{children}</a>; <MyComponent SlotComponent={CustomLink} slotComponentProps={{ href: '/test' }} /> - 传入HTML元素:
<MyComponent SlotComponent="div" slotComponentProps={{ className: 'container' }} />
内容的提问来源于stack exchange,提问作者DanielGibbs
相关产品推荐
相关产品推荐

