![](/img/trans.png)
[英]Typescript/React functional component's props function - what type?
[英]Typescript Type to accept a React component type with subset of Props
有一个带有以下道具的组件按钮:
ButtonProps = {
variant: 'primary' | 'secondary' | 'tertiary';
label: string;
// a few more props like onChange, size etc.
}
现在,我想创建另一个名为“ButtonGroup”组件的组件,该组件接受 Button 实例作为道具,但只能接受主要或次要变体。 我该如何执行?
ButtonGroup 组件如下所示:
<ButtonGroup
primaryButton={<Button variant="primary">Submit</Button>}
otherButton={<Button variant="secondary">Cancel</Button>}
/>
现在, ButtonGroup的 props 如下所示:
type PrimaryButtonProps = Omit<ButtonProps, 'variant'> & {
variant: 'primary' | 'secondary';
};
type ButtonGroupProps = BaseComponentProps<'div'> & {
size?: 'small' | 'medium';
primaryButton: React.ReactElement<PrimaryButtonProps, typeof Button>;
otherButton?: React.ReactElement<OtherButtonProps, typeof Button>;
};
我希望 primaryButton 是一个 Button 实例,它将所有 Button 道具,但将变体限制为主要或次要。 但是,通过当前的实现,如果我也提供第三变体,typescript 不会抱怨。
<ButtonGroup
primaryButton={<Button variant="tertiary">Submit</Button>} // TS SHOULD COMPLAIN BUT IT DOES NOT
/>
在我看来,最干净的解决方案是分离每个组件的实现以强制执行其特定类型。
interface ButtonProps {
variant: "primary" | "secondary" | "tertiary";
children?: React.ReactNode;
}
const Button = ({ variant, children }: ButtonProps): React.ReactElement => (
<button>{children}</button> // apply styles based on the variant
);
interface PrimaryButtonProps {
label: string;
variant: "primary" | "secondary";
}
const PrimaryButton = ({ label, variant }: PrimaryButtonProps) => (
<Button variant={{ variant }}>{{ label }}</Button>
);
因此,当您创建一个 ButtonGroup 时,您应该传递特定的 PrimaryButton 类型,而不是通用的
type ButtonGroupProps = BaseComponentProps<'div'> & {
size?: 'small' | 'medium';
primaryButton: React.ReactElement<PrimaryButtonProps, typeof PrimaryButton>;
// ...
};
<ButtonGroup
primaryButton={<PrimaryButton variant="tertiary">Submit</PrimaryButton>} // TS should complain here
/>
希望这可以帮助!
您可以使用PrimaryButton组件代替Button ,它将突出显示除primary或secondary以外的变体。
在此处检查工作的 CodeSandbox。
interface ButtonProps {
variant: "primary" | "secondary" | "tertiary";
label: string;
}
function Button({ variant, label }: ButtonProps) {
return (
<button style={{ color: variant === "primary" ? "blue" : "red" }}>
{label}
</button>
);
}
type PrimaryButtonProps = Omit<ButtonProps, "variant"> & {
variant: "primary" | "secondary";
};
interface ButtonGroupProps {
primaryButton: React.ReactElement<PrimaryButtonProps>;
}
function ButtonGroup({ primaryButton }: ButtonGroupProps) {
return <div>{primaryButton}</div>;
}
// See below type assertion. It's a hack but it works :)
const PrimaryButton = Button as (props: PrimaryButtonProps) => JSX.Element;
export default function App() {
return (
<div className="App">
<ButtonGroup
primaryButton={<PrimaryButton variant="tertiary" label="Primary" />}
/>
</div>
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.