将React中的各种接口和属性与TypeScript结合使用

huangapple go评论59阅读模式
英文:

Comine various interfaces and props in React with typescript

问题

以下是翻译好的内容:

我现在有一个像这样的接口。这代表了“基本按钮”。

export interface ButtonProps {
    backgroundColor?: Colors,
    children?: React.ReactNode | JSX.Element,
    style?: CSSProperties,
    disabled?: boolean,
    onClick?: () => void,
}

现在我想在这个基础上构建一个“文本按钮”,一个包含文本的按钮。

interface TextButtonProps {
    buttonProps?: ButtonProps,
    textColor?: Colors,
}

现在我想从`ButtonProps`中提取`backgroundColor`属性,将其用于`<TextButton />`

const TextButton = ({
                        backgroundColor,
                        textColor = 'black',
                        textProps,
                        ...buttonProps,
                    }: TextButtonProps) => {
    return (
        ...
    )
}

是否有一种方法可以使`backgroundColor``<TextButton />`中可用,而不必在`TextButtonProps`中再次明确命名它?我可以这样做:

interface TextButtonProps {
    backgroundColor?: Colors,
    buttonProps?: ButtonProps,
    textColor?: Colors,
}

但这样我会重复自己,因为`ButtonProps`已经包含了`backgroundColor`
英文:

I am having an interface like this. This represents the "base button".

export interface ButtonProps {
    backgroundColor?: Colors,
    children?: React.ReactNode | JSX.Element,
    style?: CSSProperties,
    disabled?: boolean,
    onClick?: () =&gt; void,
}

I now want to build ontop of that a "Text Button", a Button containing text.

interface TextButtonProps {
    buttonProps?: ButtonProps,
    textColor?: Colors,
}

I knwo want to extract the property backgroundColor from ButtonProps, using it in &lt;TextButton /&gt;

const TextButton = ({
                        backgroundColor,
                        textColor = &#39;black&#39;,
                        textProps,
                        ...buttonProps,
                    }: TextButtonProps) =&gt; {
    return (
        ...
    )

Is there a way to make backgroundColor available to &lt;TextButton /&gt;, without explicitly naming it again in the TextButtonProps? I could do it like this

interface TextButtonProps {
    backgroundColor?: Colors,
    buttonProps?: ButtonProps,
    textColor?: Colors,
}

But I would repeat myself, because ButtonProps contains already backgroundColor.

答案1

得分: 1

你可以保持类型不变,并将属性传递给Button

const TextButton: React.FC<TextButtonProps> = ({ textColor, buttonProps }) => (
  <Button {...buttonProps}>
    <Text color={textColor}>...</Text>
  </Button>
);

如果你需要在<TextButton>内部使用,例如ButtonProps.backgroundColor,那么你需要编写类似这样的代码<Text foreground={textColor} background={buttonProps?.backgroundColor}>。个人而言,我觉得TextButtonProps.buttonProps有点令人困惑:考虑一下调用者:

<TextButton textColor="red" buttonProps={{ backgroundColor: "green" }}>
  Click me
</TextButton>

真的令人困惑。

作为一个注释:你可以从类型中选择一个属性:

interface TextButtonProps extends Pick<ButtonProps, "backgroundColor"> {
}

但这不是我在这里会做的,我会简单地通过附加属性扩展ButtonProps接口:

interface TextButtonProps extends ButtonProps {
  textColor?: Colors;
}

然后你的组件将是:

const TextButton: React.FC<TextButtonProps> = ({ children, textColor, ...buttonProps }) => (
  <Button {...buttonProps}>
    <Text color={textColor}>{children}</Text>
  </Button>
);

额外的注释:如果你使用React.FC,你不需要声明children(我强烈建议始终这样做)。请注意,React 18的类型在一定程度上有所改变,因此你可能需要使用React.FC<React.PropsWithChildren<ButtonProps>>
还有一个:请记住,type T = { ... } & Vinterface T extends V { ... }不同(即使在大多数情况下,你可能不关心这种差异)。

英文:

You could keep your types as-is and pass the properties down to Button:

const TextButton: React.FC&lt;TextButtonProps&gt; = ({ textColor, buttonProps }) =&gt; (
  &lt;Button {...buttonProps}&gt;
    &lt;Text color={textColor}&gt;...&lt;/Text&gt;
  &lt;/Text&gt;
);

If you need to use, for example, ButtonProps.backgroundColor inside &lt;TextButton&gt; then you'd need to write something like this &lt;Text foreground={textColor} background={buttonProps?.backgroundColor}&gt;. I, personally, find TextButtonProps.buttonProps a bit confusing: think about the caller:

&lt;TextButton textColor=&quot;red&quot; buttonProps={{ backgroundColor: &quot;green&quot; }}&gt;
  Click me
&lt;/TextButton&gt;

Truly confusing.

As a note: you can pick a property from a type:

interface TextButtonProps extends Pick&lt;ButtonProps, &quot;backgroundColor&quot;&gt; {
}

But it's NOT what I'd do here, I'd simply extend the ButtonProps interface with the additional properties:

interface TextButtonProps extends ButtonProps {
  textColor?: Colors;
}

Your component will then be:

const TextButton: React.FC&lt;TextButtonProps&gt; = ({ children, textColor, ...buttonProps }) =&gt; (
  &lt;Button {...buttonProps}&gt;
    &lt;Text color={textColor}&gt;{children}&lt;/Text&gt;
  &lt;/Text&gt;
);

<hr>

An extra note: you do not need to declare children if you use React.FC (I strongly suggest to always do it). Note that types for React 18 change a bit so you might need to use React.FC&lt;React.PropsWithChildren&lt;ButtonProps&gt;&gt;.
Another one: remember that type T = { ... } &amp; V is NOT the same as interface T extends V { ... } (even if, in most cases, you probably do not care about the difference).

答案2

得分: 0

你可以使用交集(intersection)来声明具有附加属性的类型:

type TextButtonProps = ButtonProps & {
    textColor?: Colors
}
英文:

If you want to declare a type that has additional properties, you can use an intersection:

type TextButtonProps = ButtonProps &amp; {
    textColor?: Colors
}

答案3

得分: 0

试试这个,不创建额外的类型定义:

TextButtonProps & TextButtonProps[keyof TextButtonProps] 作为类型,它应该包括嵌套的类型。

const TextButton = ({
      backgroundColor,
      textColor = 'black',
      textProps,
      ...buttonProps,
}: TextButtonProps & TextButtonProps[keyof TextButtonProps] ) => {
英文:

Try this without creating an extra type definition:

TextButtonProps & TextButtonProps[keyof TextButtonProps] as type, it should take the nested types too

const TextButton = ({
      backgroundColor,
      textColor = &#39;black&#39;,
      textProps,
      ...buttonProps,
}: TextButtonProps &amp; TextButtonProps[keyof TextButtonProps] ) =&gt; {

huangapple
  • 本文由 发表于 2023年2月14日 21:17:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448409.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定