Make React props optional and required in TypeScript based on other props
P粉738046172
P粉738046172 2023-09-17 13:42:00
0
1
673

I have a React button container component that returns a regular button, an icon button, or an icon-only button based on the type provided by the prop used by the user. The following are the related type definitions of the ButtonContainer component and Props:

type ButtonWrapperProp = {
    label?:string;
    icon?:React.ReactNode;
    onClick:()=>void;
    type:'text'|'icon'|'iconOnly';

}

export const ButtonContainer = (props: ButtonWrapperProps) => {
    const {
        type = 'text',
        onClick,
        icon = <></>,
        label = '',
    } = props;

    const rendorButton = () => {
        switch (type) {
            case 'text':
                return (
                    <Button onClick={onClick}>{label}  <Button/>
                );

            case 'iconOnly':
                return (
                     <IconButton onClick={onClick}>
                       {icon}
                     </IconButton>
                );

            case 'icon':
                return (
                     <Button startIcon={icon}>
                       {label}
                     </Button>
                );

            default:
                return (
                    <Button onClick={onClick}>{label}  <Button/>
                );
        }
    };
    return <>{rendorButton()}</>;
};

Here's how I use the ButtonContainer component:

<ButtonContainer type="iconOnly" onClick={onClick} icon={<DeleteIcon />}/>
<ButtonContainer type="text" onClick={onClick} label='Text button'/>
<ButtonContainer type="icon" onClick={onClick} label='Text and icon button' icon={<DeleteIcon />}/>

In the above code, the icon prop is optional because it is only used for icon buttons with icons and regular buttons. I want the icon prop to be optional only if the type passed from ButtonContainer is text and it should be a required prop if the type passed to ButtonContainer is icon or iconOnly.

P粉738046172
P粉738046172

reply all(1)
P粉803444331

I would choose to use Distinguish the union type.

The type attribute acts as a discriminator, allowing you to narrow down ButtonWrapperProps to union members.

Also note that I can make each union member's properties required, which gives a good experience when using them - TS is smart enough to prompt which additional properties are required after the type is set .

type TextButtonProps = {
  type:'text'
  label:string;
  onClick:()=>void;
}

type IconOnlyButtonProps = {
  type:'iconOnly'
  icon:React.ReactNode;
  onClick:()=>void;
}

type IconButtonProps = {
  type:'icon'
  icon:React.ReactNode;
  label:string;
  onClick:()=>void;
}

type ButtonWrapperProps = TextButtonProps | IconOnlyButtonProps | IconButtonProps;

export const ButtonContainer = (props: ButtonWrapperProps) => {
  const renderButton = () => {
      switch (props.type) {
          case 'text':
              return (
                  <Button onClick={props.onClick}>{props.label}  </Button>
              );

          case 'iconOnly':
              return (
                   <IconButton onClick={props.onClick}>
                     {props.icon}
                   </IconButton>
              );

          case 'icon':
              return (
                   <Button startIcon={props.icon}>
                     {props.label}
                   </Button>
              );
      }
  };
  return <>{renderButton()}</>;
};
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template