如何用styled-components+TypeScript覆盖组件必填Props,避免重复传入?
嘿,我刚好碰到过类似的问题,结合你用的版本(TypeScript 3.7.5、React 16.12.0、styled-components 5.0.1),给你两个可行的解决思路,先说说你之前两种方法为啥不行,再给你具体方案:
为啥你之前的方法没生效?
- 第一种直接把
<Icon icon={"ArrowRight"}/>传给styled:styled接收的是组件构造函数/函数组件,不是已经渲染的JSX元素,所以这种方式根本不会正确生成带预设属性的styled组件,反而会创建一个包裹这个元素的容器,完全达不到你要的效果。 - 第二种设置
defaultProps:TypeScript 3.x版本对defaultProps的类型支持有缺陷,尤其是和styled-components结合时,不会自动把必填属性标记为可选,所以TS还是会强制你传入icon,而且styled-components在5.0.1版本也没完全处理好这种场景的类型推断。
可行方案一:用styled-components的attrs+类型扩展
attrs是styled-components专门用来设置默认属性的API,再配合TypeScript的类型修改,就能让TS认可我们已经预设了必填属性:
import styled from 'styled-components'; // 假设你的Icon组件类型是这样的 interface IconProps { icon: string; // 其他可能的属性,比如size、color等 } const Icon: React.FC<IconProps> = ({ icon, ...props }) => { // 你的Icon组件实现 }; // 定义Arrow的Props:去掉必填的icon,或者把它设为可选 type ArrowProps = Omit<IconProps, 'icon'>; // 用attrs预设icon属性,再通过类型断言让TS知道icon不需要传入 const Arrow = styled(Icon).attrs({ icon: 'ArrowRight', })` // 你的样式代码,比如: width: 24px; height: 24px; color: #1890ff; ` as React.ComponentType<ArrowProps>; // 现在使用<Arrow />就不需要传icon了,TS也不会报错!
可行方案二:先写包装组件再套styled
这个方案更直观,类型也更安全,不需要类型断言:
import styled from 'styled-components'; // 先创建一个预设了icon的基础组件,它只接收IconProps里除了icon之外的属性 const ArrowBase: React.FC<Omit<IconProps, 'icon'>> = (props) => { return <Icon icon="ArrowRight" {...props} />; }; // 再用styled包裹这个基础组件,添加样式 const Arrow = styled(ArrowBase)` // 你的样式代码 width: 24px; height: 24px; color: #1890ff; `; // 使用<Arrow />时,完全不需要传icon,TS会自动检查其他属性
总结
推荐用方案二,因为它逻辑清晰,类型推断更准确,不需要额外的类型断言;如果觉得多写一个包装组件麻烦,方案一的attrs+类型修改也能解决问题,适配你当前的版本。
内容的提问来源于stack exchange,提问作者Joakim Jäderberg
相关产品推荐
相关产品推荐

