React 19+TypeScript中如何高效复用AllHTMLAttributes接口?
React 19 中复用HTML元素属性类型的简化方案
你不需要为每个组件单独创建重复的接口,可以通过泛型类型复用的方式,在保留TypeScript类型安全性的同时彻底消除重复代码。
核心思路:创建通用HTML组件属性类型
利用TypeScript泛型封装一个可复用的类型,它自动继承对应HTML元素的所有属性,并包含ref类型。由于AllHTMLAttributes<T>已经内置了className、children等通用属性,不需要额外重复定义。
import { AllHTMLAttributes, Ref } from 'react'; // 通用泛型类型:适配任意HTML元素的属性+ref type HTMLComponentProps<T extends HTMLElement> = AllHTMLAttributes<T> & { ref?: Ref<T>; };
直接复用通用类型编写组件
针对Section、Card、CardHeader这类基于HTML元素的组件,直接使用上述泛型类型,指定对应的HTML元素类型即可:
import clsx from 'clsx'; // Section组件(基于div) export const Section = ({ className, ref, ...props }: HTMLComponentProps<HTMLDivElement>) => ( <div className={clsx("section", className)} ref={ref} {...props} /> ); // Card组件(基于div) export const Card = ({ className, ref, ...props }: HTMLComponentProps<HTMLDivElement>) => ( <div className={clsx("card", className)} ref={ref} {...props} /> ); // CardHeader组件(基于div) export const CardHeader = ({ className, ref, ...props }: HTMLComponentProps<HTMLDivElement>) => ( <div className={clsx("card-header", className)} ref={ref} {...props} /> ); // 如果是基于按钮的组件,只需替换HTML元素类型 export const Button = ({ className, ref, ...props }: HTMLComponentProps<HTMLButtonElement>) => ( <button className={clsx("custom-btn", className)} ref={ref} {...props} /> );
扩展自定义属性(按需)
如果某个组件需要额外的自定义属性,只需扩展通用类型即可,不影响复用性:
// 带自定义属性的Card组件 type CardProps = HTMLComponentProps<HTMLDivElement> & { isElevated?: boolean; // 自定义属性 }; export const Card = ({ className, isElevated, ref, ...props }: CardProps) => ( <div className={clsx("card", isElevated && "card-elevated", className)} ref={ref} {...props} /> );
为什么这是最佳实践?
- 完全消除重复代码:所有基于HTML元素的组件共享同一套类型定义
- 严格的类型安全:自动继承对应HTML元素的所有属性,避免类型遗漏
- 灵活扩展:支持按需添加自定义属性,不破坏复用逻辑
内容的提问来源于stack exchange,提问作者Raphael Elias
相关产品推荐
相关产品推荐

