简体   繁体   中英

Typescript: Argument of type X is not assignable to parameter of type Y & X. Type X is not assignable to type Y

For a button link component, I'm trying to choose between HTMLButtonAttributes or HTMLAnchorAttributes based on passed props. My knowledge of TypeScript is quite limited.

I have the following types and interfaces:

interface CommonButtonProps {
   // custom props
}

export interface ButtonProps extends CommonButtonProps,
    React.ButtonHTMLAttributes<HTMLButtonElement> {}

export interface ButtonLinkProps extends CommonButtonProps,
    React.AnchorHTMLAttributes<HTMLAnchorElement> {
  href: string;
}

export type ButtonOrButtonLinkProps = ButtonProps | ButtonLinkProps;

export const isButtonLink = (props: ButtonOrButtonLinkProps,): props is ButtonLinkProps => guard logic

And the following Button component with ButtonOrButtonLinkProps:

export const Button: React.FC<ButtonOrButtonLinkProps> = props => {
  const buttonLink = isButtonLink(props);

  const commonProps = {
  };

  const linkProps: ButtonLinkProps = {
    ...commonProps,
    onClick: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
      // Do stuff
      if (props.onClick) {
        props.onClick(event); // Error
      }
    },
  };


  const buttonProps: ButtonProps = {
    ...commonProps,
    type: 'button',
    onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
      // Do other stuff
      if (props.onClick) {
        props.onClick(event); // Error
      }
    },
  };

  return (
    <StyledBtn {...(buttonLink ? linkProps : buttonProps)}>
      {children}
    </StyledBtn>
  );
};

The following line throws an error:

  if (props.onClick) {
    props.onClick(event); // Error
  }

Argument of type 'MouseEvent<HTMLButtonElement, MouseEvent>' is not assignable to parameter of type 'MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent<HTMLAnchorElement, MouseEvent>'. Type 'MouseEvent<HTMLButtonElement, MouseEvent>' is not assignable to type 'MouseEvent<HTMLAnchorElement, MouseEvent>'. Type 'HTMLButtonElement' is missing the following properties from type 'HTMLAnchorElement': charset, coords, download, hreflang, and 19 more.

It seems the current type of onClick is在此处输入图片说明

Why is the event type and intersection of MouseEvent of HTMLButtonElement & MouseEvent of HTMLAnchorElement ? I kinda expected it to be an union - either one or the other ?

Any idea how to fix the issue ?

Probably you shouldn't do it this way

Your component's props is public API of isolated code block, so you don't want to expand it too far. The best solution would be not to include all of link/button props into Button props, but include only necessary ones

But if you have to

The problem is that typescript does not understand what onClick type is, because it can be different based on props you pass. By the time typescript comes to props.onClick(execution) there are still ambiguity in type of props.

Solution

Use your typeguard to let typescript know what type of props is

export const Button: React.FC<...> = props => {
  // props is of type `ButtonProps | ButtonLinkProps` here
  // so `onClick` is ambiguous too

  if (isButtonLink(props)) {
    // Do button link stuff
    // props is of type `ButtonLinkProps` here
  } else {
    // Do button stuff
    // props is of type `ButtonProps` here
  }

  // props is again of type `ButtonProps | ButtonLinkProps` here
  
  return (...);
}

Playground link on typeguards

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM