There is a ponent Button with following props:
ButtonProps = {
variant: 'primary' | 'secondary' | 'tertiary';
label: string;
// a few more props like onChange, size etc.
}
Now, I want to create another ponent called "ButtonGroup" ponent that accepts a Button instance as a prop but can only accept primary or secondary variant. How can I enforce that?
ButtonGroup ponent looks this:
<ButtonGroup
primaryButton={<Button variant="primary">Submit</Button>}
otherButton={<Button variant="secondary">Cancel</Button>}
/>
Now, the props for ButtonGroup are as follwos:
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>;
};
I expect primaryButton to be a Button instance will all Button props but restricting variant to be either primary or secondary. But, with this current implementation, typescript doesn't plain if I provide a tertiary variant too.
<ButtonGroup
primaryButton={<Button variant="tertiary">Submit</Button>} // TS SHOULD COMPLAIN BUT IT DOES NOT
/>
There is a ponent Button with following props:
ButtonProps = {
variant: 'primary' | 'secondary' | 'tertiary';
label: string;
// a few more props like onChange, size etc.
}
Now, I want to create another ponent called "ButtonGroup" ponent that accepts a Button instance as a prop but can only accept primary or secondary variant. How can I enforce that?
ButtonGroup ponent looks this:
<ButtonGroup
primaryButton={<Button variant="primary">Submit</Button>}
otherButton={<Button variant="secondary">Cancel</Button>}
/>
Now, the props for ButtonGroup are as follwos:
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>;
};
I expect primaryButton to be a Button instance will all Button props but restricting variant to be either primary or secondary. But, with this current implementation, typescript doesn't plain if I provide a tertiary variant too.
<ButtonGroup
primaryButton={<Button variant="tertiary">Submit</Button>} // TS SHOULD COMPLAIN BUT IT DOES NOT
/>
Share
Improve this question
asked Aug 29, 2022 at 17:28
AshimaAshima
4,8346 gold badges41 silver badges64 bronze badges
3
- 1 AFAIK this is not possible: stackoverflow./q/42955400/4980215 – Ivan Shumilin Commented Sep 1, 2022 at 11:56
- Would it be acceptable to just take in the primary button props and render the Button inside the ButtonGroup? – AlienWithPizza Commented Sep 2, 2022 at 1:42
- This is a problem due to React, not Typescript. Check out this Playground where the type inference works fine and properly allows me to do what you're trying to do to above: typescriptlang/play?#code/… I'd also go with what @adrisons is suggesting, it makes more sense any way. – Forrest Commented Sep 6, 2022 at 6:29
2 Answers
Reset to default 4 +25In my opinion the cleanest solution would be to separate the implementation of each ponent to enforce its specific types.
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>
);
So, when you create a ButtonGroup, you should pass the specific PrimaryButton type, instead the generic one
type ButtonGroupProps = BaseComponentProps<'div'> & {
size?: 'small' | 'medium';
primaryButton: React.ReactElement<PrimaryButtonProps, typeof PrimaryButton>;
// ...
};
<ButtonGroup
primaryButton={<PrimaryButton variant="tertiary">Submit</PrimaryButton>} // TS should plain here
/>
Hope this helps!
You can use PrimaryButton ponent instead of Button and it will highlight the variant other than primary or secondary.
Checkout the working CodeSandbox here.
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>
);
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744977471a4604234.html
评论列表(0条)