Typescript: аргумент типа X не может быть присвоен параметру типа Y

#javascript #reactjs #typescript #typescript-generics

#javascript #reactjs #typescript #typescript-generics

Вопрос:

Для компонента ссылки на кнопку я пытаюсь выбрать между HTMLButtonAttributes или HTMLAnchorAttributes на основе переданных реквизитов. Мои знания TypeScript довольно ограничены.

У меня есть следующие типы и интерфейсы:

 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
  

И следующий компонент Button с buttonorbuttonlink сбрасывает:

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

Следующая строка выдает ошибку:

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

Аргумент типа ‘MouseEvent<HTMLButtonElement, MouseEvent>’ не
может быть присвоен параметру типа ‘MouseEvent<HTMLButtonElement,
MouseEvent> amp; MouseEvent<HTMLAnchorElement, MouseEvent>’. Тип
‘MouseEvent<HTMLButtonElement, MouseEvent>’ не может быть присвоен типу
‘MouseEvent<HTMLAnchorElement, MouseEvent>’ .
У типа ‘HTMLButtonElement’ отсутствуют следующие свойства из типа ‘HTMLAnchorElement’: charset, coords, download, hreflang и
еще 19.

Кажется onClick , текущий тип введите описание изображения здесь

Почему тип события и пересечение MouseEvent HTMLButtonElement amp; MouseEvent HTMLAnchorElement ? Я как бы ожидал, что это будет объединение — либо одно, либо другое?

Есть идеи, как исправить проблему?

Комментарии:

1. пожалуйста, укажите структуру вашего кода в codesandbox

Ответ №1:

Вероятно, вам не следует делать это таким образом

Реквизит вашего компонента является общедоступным API изолированного блока кода, поэтому вы не хотите расширять его слишком далеко. Лучшим решением было бы не включать все реквизиты ссылки / кнопки в реквизит Button , а включать только необходимые

Но если вам нужно

Проблема в том, что typescript не понимает, что onClick такое тип, потому что он может отличаться в зависимости от передаваемых вами реквизитов. К тому времени, когда typescript приходит к props.onClick(execution) , все еще остается неопределенность в типе реквизитов.

Решение

Используйте свой typeguard, чтобы typescript знал, какой тип реквизита

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

Ссылка на игровую площадку в typeguards