如何无需显式声明,让TextButton继承ButtonProps的所有属性?
问题描述
现有Button组件及对应的ButtonProps接口如下:
interface ButtonProps { children?: React.ReactNode, backgroundColor?: Colors, style?: object, disabled?: boolean, classes?: string onClick?: () => void } const Button = ({ backgroundColor, classes, children, disabled = false, onClick, style, }: ButtonProps) => { const _constructInlineStyles = (): CSSProperties => { ... } return ( <button className={clsx(classes, 'button-container')} disabled={disabled} onClick={onClick} style={...}> {children} </button> ) } export default Button;
基于该Button封装TextButton的初始实现为:
interface TextButtonProps { children: string; } const TextButton = ({ children, }: TextButtonProps) => { return ( <Button> <Text> {children} </Text> </Button> ) } export default TextButton;
需求是无需显式列出ButtonProps的每个属性,让TextButton支持ButtonProps的所有属性,不想采用这种逐个声明属性的繁琐写法:
interface TextButtonProps { children: string; } const TextButton = ({ children, backgroundColor, classes, disabled = false, onClick, style, }: TextButtonProps & ButtonProps ) => { return ( <Button className={classes} disabled={disabled} onClick={onClick} style={style}> <Text> {children} </Text> </Button> ) }
想问是否可以用类似下面的写法,让TextButton直接接收ButtonProps的属性(比如直接写<TextButton disabled={true}>Fooo</TextButton>):
interface TextButtonProps { children: string; props: ButtonProps; } const TextButton = ({ children, props, }: TextButtonProps) => { return ( <Button {...props}> <Text> {children} </Text> </Button> ) }
解决方案
你提到的写法无法实现<TextButton disabled={true}>Fooo</TextButton>这种直接传参的效果——这种写法要求必须把Button的所有属性都嵌套在props对象里使用,比如得写成:
<TextButton props={{ disabled: true }}>Fooo</TextButton>
这显然不符合你的需求。
正确的实现方式是让TextButtonProps继承ButtonProps,同时覆盖children的类型(因为你需要TextButton的children是string,而Button的是ReactNode),再通过剩余属性语法接收所有ButtonProps的其他属性,最后用展开运算符传给Button组件。
具体代码如下:
// 继承ButtonProps并覆盖children的类型约束 interface TextButtonProps extends ButtonProps { children: string; } const TextButton = ({ children, ...restProps // 接收除children外的所有ButtonProps属性 }: TextButtonProps) => { return ( <Button {...restProps}> {/* 把所有继承来的属性展开传给Button */} <Text>{children}</Text> </Button> ) } export default TextButton;
这种写法的优势:
- 无需逐个声明ButtonProps的属性,自动继承所有属性
- 直接支持
<TextButton disabled={true} backgroundColor="red">Fooo</TextButton>这种直观写法 - 保留了TextButton对children的类型约束(必须为string)
- 维护性高:后续ButtonProps新增属性时,TextButton会自动支持,无需额外修改
内容的提问来源于stack exchange,提问作者four-eyes
相关产品推荐
相关产品推荐

