【问题标题】:Styled Components .attrs w/ TypeScript带有 TypeScript 的样式化组件 .attrs
【发布时间】: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 文档在这方面不是很清楚。非常感谢您朝着正确的方向前进。

【问题讨论】:

    标签: reactjs typescript 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&lt;"div", any, {}, never&gt;

    理想情况下,它类似于ThemedStyledFunction&lt;"div", any, StyleProps &amp; IBottleComponentProps, "style" | "fill"&gt;

    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(&quot;/media/images/image_file.png&quot;);" 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&lt;C, T, O &amp; NewA, A | keyof NewA&gt;:

      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

      【讨论】:

      猜你喜欢
      • 2021-02-04
      • 2020-11-05
      • 2019-08-20
      • 2020-07-12
      • 2019-11-12
      • 2019-10-27
      • 2021-10-23
      • 2020-07-16
      • 2017-10-23
      相关资源
      最近更新 更多