React函数组件中TypeScript的...rest属性声明问题
如何在React+TypeScript组件中正确声明...rest属性
问题场景
开发React函数组件结合TypeScript时,使用...rest传递额外属性(如className)遇到两类类型错误:
- 父组件传递
className给Button组件时,提示Property 'className' does not exist on type 'IntrinsicAttributes & Props' - 组件内部访问
rest.className时,提示Property 'className' does not exist on type '{ rest?: any; }'
原写法错误地在Props接口中添加rest字段接收剩余属性,不符合TypeScript对剩余属性的处理逻辑。
正确解决方案
方法1:让Props接口继承原生button元素属性
让自定义Props直接继承React.ButtonHTMLAttributes<HTMLButtonElement>,自动包含所有原生button属性(如className、onClick等),同时保留自定义属性:
import { ReactNode, ButtonHTMLAttributes } from 'react'; import className from 'classnames'; import PropTypes from 'prop-types'; // 继承原生button所有属性,添加自定义属性 interface Props extends ButtonHTMLAttributes<HTMLButtonElement> { children: ReactNode; primary?: boolean; secondary?: boolean; success?: boolean; warning?: boolean; danger?: boolean; outline?: boolean; rounded?: boolean; } function Button({ children, primary, secondary, success, warning, danger, outline, rounded, // 直接解构剩余属性,无需在Props中定义rest字段 ...rest }: Props) { const classes = className( rest.className, // 可正常访问className 'flex items-center px-3 py-1.5 border transition', { 'border-blue-500 bg-blue-500 text-white hover:bg-blue-600': primary, 'border-gray-800 bg-gray-800 text-white hover:bg-gray-900': secondary, 'border-green-500 bg-green-500 text-white hover:bg-green-600': success, 'border-yellow-500 bg-yellow-500 text-white hover:bg-yellow-600': warning, 'border-red-500 bg-red-500 text-white hover:bg-red-600': danger, 'rounded-full': rounded, 'bg-white': outline, 'text-blue-500': outline && primary, 'text-gray-800': outline && secondary, 'text-green-500': outline && success, 'text-yellow-500': outline && warning, 'text-red-500': outline && danger, } ); if ( Number(!!primary) + Number(!!secondary) + Number(!!success) + Number(!!warning) + Number(!!danger) > 1 ) { return ( <button className={classes}>Please select only one variation!!!</button> ); } return ( <button className={classes} {...rest}> {children} </button> ); } export default Button;
方法2:使用交叉类型组合自定义属性与原生属性
若不想直接继承,可通过交叉类型合并自定义属性和原生button属性:
import { ReactNode, ButtonHTMLAttributes } from 'react'; // 交叉类型:自定义属性 + 原生button属性 type Props = { children: ReactNode; primary?: boolean; secondary?: boolean; success?: boolean; warning?: boolean; danger?: boolean; outline?: boolean; rounded?: boolean; } & ButtonHTMLAttributes<HTMLButtonElement>;
后续组件解构和使用逻辑与方法1完全一致。
关键说明
- 不要在Props接口中定义
rest字段:...rest是ES6解构语法,用于提取Props中未显式声明的剩余属性,这些属性的类型需由Props接口本身通过继承或交叉类型包含,而非作为单独字段存在。 - 继承
ButtonHTMLAttributes<HTMLButtonElement>会自动覆盖所有原生button支持的属性,无需手动声明。
内容的提问来源于stack exchange,提问作者rasidagac
相关产品推荐
相关产品推荐

