搜索

首页  >  问答  >  正文

基于其他 props,使 React props 在 TypeScript 中成为可选和必需的

我有一个React按钮容器组件,根据用户使用的prop提供的类型,返回一个常规按钮、图标按钮或仅图标按钮。以下是ButtonContainer组件与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()}</>;
};

以下是我如何使用ButtonContainer组件:

<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 />}/>

在上面的代码中,icon prop是可选的,因为它只用于带有图标的图标按钮和常规按钮。我希望只有当从ButtonContainer传递的类型为text时,icon prop才是可选的;如果传递给ButtonContainer的类型是icon或iconOnly,则它应该是一个必需的prop。

P粉738046172P粉738046172477 天前704

全部回复(1)我来回复

  • P粉803444331

    P粉8034443312023-09-18 12:22:20

    我会选择使用辨别联合类型

    type属性作为一个辨别器,允许你将ButtonWrapperProps缩小到联合成员。

    还要注意,我可以将每个联合成员的属性设为必需的,这样在使用时可以获得良好的体验 - 在设置了类型后,TS足够智能,能够提示哪些额外的属性是必需的。

    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()}</>;
    };
    

    回复
    0
  • 取消回复