样式化组件 TypeScript

Posted

技术标签:

【中文标题】样式化组件 TypeScript【英文标题】:Styled Components TypeScript 【发布时间】:2019-10-27 11:36:27 【问题描述】:

使用styled-components,使用普通的 React.js 我可以这样做:

const Container = styled.div(
  userSelect: `none !important`,
)

但是使用 TypeScript 我得到了错误:

Argument of type ' userSelect: string; ' is not assignable to parameter of type 'TemplateStringsArray'.
  Object literal may only specify known properties, and 'userSelect' does not exist in type 'TemplateStringsArray'.ts(2345)

解决此问题的最佳方法是什么?

我不想使用styled.div 模板字符串方法,因为我发现它不太灵活。

例如,对于模板字符串,我们不能这样做:

const flex = 
  flex: display: flex,
  col: flexDirection: `column`


const FlexRow = styled.div(
  ...flex.flex,
)

const FlexCol = styled.div(
   ...flex.flex,
   ...flex.col,
)

【问题讨论】:

你在使用什么styled 库?您能否提供其文档或 NPM 包的链接。 糟糕,抱歉。现已添加。 还有一些 ts 类型不准确... 如果里面没有变量,为什么要使用模板字符串?为什么不只是普通的字符串?或者这只是一个例子? 如果你的意思是Container,它应该不会有什么不同。我更喜欢反引号而不是单引号。这只是一个例子:) 【参考方案1】:

更新:经过进一步调查,在我弄清楚实际情况之前,@Vincent 似乎走在了正确的轨道上。

import styled,  CSSObject  from "styled-components";

const Container = styled.div(
  userSelect: "none !important"
 as CSSObject);

会产生如下错误:

Conversion of type ' userSelect: "none !important"; ' to type 'CSSObject' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type ' userSelect: "none !important"; ' is not comparable to type 'Properties<string | number>'.
    Types of property 'userSelect' are incompatible.
      Type '"none !important"' is not comparable to type '"contain" | "all" | "-moz-initial" | "inherit" | "initial" | "revert" | "unset" | "auto" | "none" | "text" | "-moz-none" | "element" | undefined'.ts(2352)

所以是的,即使在 TypeScript 中,样式化组件也确实支持这种语法,只是它不理解 !important 后缀。这是您可能更喜欢的稍微修改的解决方案:

const important = <T extends string>(s: T): T => `$s !important` as T;

const Container = styled.div(
  userSelect: important("none"),
);

这有点 hacky(将 "none !important" 转换为 "none",但显然不是),但它可以让您的样式化 CSS 道具保持清洁并通过类型检查。


原答案:我不熟悉样式化组件的语法(它看起来有点像 JSS,但不完全一样)。

我建议使用标准语法。样式化的组件通常是这样写的:

const Container = styled.div`
  user-select: none !important;
`;

【讨论】:

感谢您的建议,但我不喜欢这种语法,因为我不能只合并样式对象,这很烦人。 @JonasWilms 谢谢。我会看看我是否可以将它纳入我的答案。 非常酷,感谢您的全面回答。还要感谢@Vincent!【参考方案2】:

它无法识别!important,因此只需将其转换为任何安静的打字稿即可。

styled.div(
  userSelect: 'none !important'  as any
);

编辑 - 解释为什么这样做

它非常简单。如果您使用类似 atom 的 ide,您可以“转到” userSelect 属性的类型。类型是UserSelectProperty,它的值必须是其中之一。

export type Globals = "-moz-initial" | "inherit" | "initial" | "revert" | "unset";
export type UserSelectProperty = Globals | "-moz-none" | "all" | "auto" | "contain" | "element" | "none" | "text";

由于none !important 不是一个选项,您必须将其转换为任何选项。

【讨论】:

可能 Typescript 需要一些字符串文字类型的组合语法 ... :) 嗯,这实际上修复了错误。你能解释一下这里发生了什么吗? @Vencovsky “正常”字符串也会发生同样的错误。【参考方案3】:

我在寻找稍微相关的东西时遇到了这个问题。我知道它已经解决了,但是我已经使用 styled-components 很长一段时间了,并且从未碰巧看到您所指的对象语法,我认为这包括在内是为了允许其他 css-in-js 选项采用。

但是,我评论的原因是您的 flex 示例,您可以使用标记的模板文字实现非常相似的效果:

const flex = 
  flex: 'display: flex',
  col: 'flex-direction: column'


const FlexRow = styled.div`
  $flex.flex;
`

const FlexCol = styled.div`
  $flex.flex;
  $flex.col;
`

快乐的样式化组件?

【讨论】:

感谢您的评论——我知道,我更喜欢对象表示法有两个原因。 1.) 我发现为常用组合创建混音要容易得多,并且 2.) 因为您可以将样式对象合并在一起。

以上是关于样式化组件 TypeScript的主要内容,如果未能解决你的问题,请参考以下文章

在样式化组件中设置 React 组件道具

如何将样式化组件作为属性添加到 TypeScript 中的另一个样式化组件?

样式化组件组织[关闭]

样式化组件中子组件输入焦点的样式父组件

样式化组件不会覆盖内联样式

样式化组件中的动态主题