带有 TypeScript 的样式化组件 .attrs
Posted
技术标签:
【中文标题】带有 TypeScript 的样式化组件 .attrs【英文标题】:Styled Components .attrs w/ TypeScript 【发布时间】:2020-09-10 17:21:57 【问题描述】:我对如何将 .attrs()
函数与 TypeScript 一起使用有点困惑。假设我有以下内容:
BottleBar.tsx:
interface IBottleComponentProps
fill?: boolean
const BottleComponent = styled.div.attrs<IBottleComponentProps>((fill) => (
style:
backgroundImage: `url("./media/images/$fill ? 'Bottle-Filled.png' : 'Bottle-Empty.png'")`
))<IBottleComponentProps`
width: 20px;
height: 20px;
`;
export default function BottleBar()
return (
<Wrapper>
<BottleComponent />
<BottleComponent fill />
</Wrapper>
)
现在,上面的代码有效,但我不确定为什么在开头和结尾都需要两次 IBottleComponentProps
- 如果没有它,我会得到以下信息:
Type ' fill: boolean; ' is not assignable to type 'IntrinsicAttributes & Pick<Pick<Pick<DetailedhtmlProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "slot" | ... 253 more ... | "onTransitionEndCapture"> & ...; , "slot" | ... 254 more ... | "onTransitionEndCapture"> & Partial<...>, "slot" | ... 254 more ... | "onTransitionEndCapture"> & ...; & ...; '.
另外,在第一个代码示例中,我得到了一个浏览器日志;
index.js:1 Warning: Received `true` for a non-boolean attribute `fill`.
老实说,这很令人困惑,并且 Styled-Components 文档在这方面不是很清楚。非常感谢您朝着正确的方向前进。
【问题讨论】:
【参考方案1】:看起来第二种类型的变量信息正在丢失第一种类型的信息。
这是attr
的定义
export interface ThemedStyledFunction<
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
T extends object,
O extends object = ,
A extends keyof any = never
> extends ThemedStyledFunctionBase<C, T, O, A>
// Fun thing: 'attrs' can also provide a polymorphic 'as' prop
// My head already hurts enough so maybe later...
attrs<
U,
NewA extends Partial<StyledComponentPropsWithRef<C> & U> &
[others: string]: any;
=
>(
attrs: Attrs<StyledComponentPropsWithRef<C> & U, NewA, T>
): ThemedStyledFunction<C, T, O & NewA, A | keyof NewA>;
根据NewA
类型变量应该有来自U
类型的必要信息。
然而结果是ThemedStyledFunction<"div", any, , never>
理想情况下,它类似于ThemedStyledFunction<"div", any, StyleProps & IBottleComponentProps, "style" | "fill">
type IBottleComponentProps =
fill?: boolean
type StyleProps =
style:
backgroundImage: string;
const BottleComponent = styled.div.attrs<IBottleComponentProps, StyleProps & IBottleComponentProps>((fill) => (
style:
backgroundImage: `url("")`
))`
width: 20px;
height: 20px;
`;
【讨论】:
【参考方案2】:答案 1:Warning about fill
您需要为您的样式化组件选择一个不同的名称,可能是full
,但不是fill
。因为fill
是一些 HTML 元素的标准属性。 Also, at w3schools
实验:
如果您将fill
声明为string
并传递一个字符串值,您可以看到在HTML DOM 中将fill
属性添加到div
,例如:
<div
fill="test"
style="background-image: url("/media/images/image_file.png");" class="sc-AxiKw jDjxaQ">
</div>
fill
是 SVGAttributes 接口中的一个属性:
来自node_modules/@types/react/index.d.ts
:
interface SVGAttributes<T> extends AriaAttributes, DOMAttributes<T>
// Attributes which also defined in HTMLAttributes
className?: string;
id?: string;
...
// SVG Specific attributes
accentHeight?: number | string;
...
fill?: string;
...
这就是这个警告的原因:
Warning: Received `true` for a non-boolean attribute `fill`.
If you want to write it to the DOM, pass a string instead: fill="true" or fill=value.toString().
答案 2:Why interface is required 2 times?
以下是相关界面的摘录:
attrs<
U,
NewA extends Partial<StyledComponentPropsWithRef<C> & U> &
[others: string]: any;
=
>(
attrs: Attrs<StyledComponentPropsWithRef<C> & U, NewA, T>
): ThemedStyledFunction<C, T, O & NewA, A | keyof NewA>;
U
变成:IBottleComponentProps
你传递
C
是 HTML 元素或反应组件类型
并且返回类型是ThemedStyledFunction<C, T, O & NewA, A | keyof NewA>
:
export interface ThemedStyledFunction<
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
T extends object,
O extends object = ,
A extends keyof any = never
C
, T
已经提供。您通过第二次传递IBottleComponentProps
来提供O
。
如果您不提供它,您的BottleComponent
将如下所示,其中 用于道具,即没有道具:
如果您提供,它将如下图所示,并带有正确的道具。
简而言之,您现在必须提供 2 次接口。如果你没有定义你的接口,你可以提供any
。
【讨论】:
如果这在任何地方都有记录,那就太好了。非常感谢您的解决方案和出色的解释。 仅供参考,现在也可以在github.com/DefinitelyTyped/DefinitelyTyped/issues/…找到 在github.com/styled-components/styled-components-website/pull/775开了一个PR以上是关于带有 TypeScript 的样式化组件 .attrs的主要内容,如果未能解决你的问题,请参考以下文章
带有 Typescript 和 ThemeProvider 的样式化组件。啥是正确的类型?
包括对带有 typescript 的样式化组件主题的媒体查询
使用带有 typescript 的样式化组件“as”prop