英文:
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?: () => 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 <TextButton />
const TextButton = ({
backgroundColor,
textColor = 'black',
textProps,
...buttonProps,
}: TextButtonProps) => {
return (
...
)
Is there a way to make backgroundColor
available to <TextButton />
, 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 = { ... } & V
与interface T extends V { ... }
不同(即使在大多数情况下,你可能不关心这种差异)。
英文:
You could keep your types as-is and pass the properties down to Button
:
const TextButton: React.FC<TextButtonProps> = ({ textColor, buttonProps }) => (
<Button {...buttonProps}>
<Text color={textColor}>...</Text>
</Text>
);
If you need to use, for example, ButtonProps.backgroundColor
inside <TextButton>
then you'd need to write something like this <Text foreground={textColor} background={buttonProps?.backgroundColor}>
. I, personally, find TextButtonProps.buttonProps
a bit confusing: think about the caller:
<TextButton textColor="red" buttonProps={{ backgroundColor: "green" }}>
Click me
</TextButton>
Truly confusing.
As a note: you can pick a property from a type:
interface TextButtonProps extends Pick<ButtonProps, "backgroundColor"> {
}
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<TextButtonProps> = ({ children, textColor, ...buttonProps }) => (
<Button {...buttonProps}>
<Text color={textColor}>{children}</Text>
</Text>
);
<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<React.PropsWithChildren<ButtonProps>>
.
Another one: remember that type T = { ... } & 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 & {
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 = 'black',
textProps,
...buttonProps,
}: TextButtonProps & TextButtonProps[keyof TextButtonProps] ) => {
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论