首页 > 解决方案 > TypeScript with React - 试图从 React 类型中定义的 HTMLProps 中省略一个属性

问题描述

我正在使用 React 和 TypeScript 开发一个组件库。

我目前正在创建一个工具提示组件。

在 types.ts 文件中,我定义了这个组件的类型。代码:

import { DetailedHTMLProps, HTMLAttributes, ReactNode } from 'react';

export type TooltipPosition = 'top' | 'right' | 'bottom' | 'left';
export type TooltipTrigger = 'hover' | 'click';

type HTMLDivProps = DetailedHTMLProps<
  HTMLAttributes<HTMLDivElement>,
  HTMLDivElement
>;

export interface TooltipProps extends Omit<HTMLDivProps, 'title'> {
  /**
   * Tooltip title
   */
  title: ReactNode;
  /**
   * If true, Tooltip will be visible
   */
  isVisible?: boolean;
  /**
   * Tooltip position
   */
  position?: TooltipPosition;
  /**
   * Event must be triggered to display Tooltip
   */
  trigger?: TooltipTrigger;
  /**
   * if true, this will keep the tooltip active even if the mouse is outside the trigger element
   */
  interactive?: boolean;
  /**
   * The number of milliseconds to wait before showing the tooltip.
   */
  enterDelay?: number;
  /**
   * The number of milliseconds to wait before hiding the tooltip.
   */
  hideDelay?: number;
  /**
   * Tooltip children
   */
  children?: ReactNode;
}

问题是 Omit 似乎不起作用。即使试图省略“标题”,TypeScript 仍然声称我定义的类型不适用于 TypeScript 中的明确样式。

错误:

Error:(52, 51) TS2769: No overload matches this call.
  Overload 1 of 2, '(props: Pick<Pick<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "title" | "key" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & TooltipProps, "ref" | ... 260 more ... | "hideDelay"> & Partial<...>, "ref" | ... 260 more ... | "hideDelay"> & { ...; } & { ...; }): ReactElement<...>', gave the following error.
    Type 'ReactNode' is not assignable to type 'string | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | (string & ReactNodeArray) | (string & ReactPortal) | undefined'.
      Type 'null' is not assignable to type 'string | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | (string & ReactNodeArray) | (string & ReactPortal) | undefined'.
  Overload 2 of 2, '(props: StyledComponentPropsWithAs<"div", DefaultTheme, TooltipProps, never>): ReactElement<StyledComponentPropsWithAs<"div", DefaultTheme, TooltipProps, never>, string | ... 1 more ... | (new (props: any) => Component<...>)>', gave the following error.
    Type 'ReactNode' is not assignable to type 'string | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | (string & ReactNodeArray) | (string & ReactPortal) | undefined'.
      Type 'null' is not assignable to type 'string | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | (string & ReactNodeArray) | (string & ReactPortal) | undefined'.

我的组件:

import React, { useState, useEffect, useRef } from 'react';
import { TooltipProps } from './types';
import { INITIAL_IS_VISIBLE } from './config';
import { TooltipContainer, TooltipStyled } from './styles';

const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>((props, ref) => {
  const {
    children,
    enterDelay,
    hideDelay,
    interactive,
    position,
    title,
    trigger,
    isVisible,
  } = props;

  const [isTooltipVisible, setIsTooltipVisible] = useState<boolean>(
    INITIAL_IS_VISIBLE
  );

  // Settings refs
  const wrapper =
    (ref as React.RefObject<HTMLDivElement>) ||
    React.useRef<HTMLDivElement>(null);

  const handleVisibility = (e: MouseEvent | React.SyntheticEvent) => {
    if (wrapper?.current && !wrapper?.current.contains(e.target as Node)) {
      return setIsTooltipVisible(false);
    }
    return setIsTooltipVisible(prevVisibility => !prevVisibility);
  };

  // eslint-disable-next-line consistent-return
  useEffect(() => {
    if (trigger === 'click') {
      document.addEventListener('click', handleVisibility);
      return () => {
        document.removeEventListener('click', handleVisibility);
      };
    }
  }, []);

  return (
    <TooltipContainer
      ref={wrapper}
      onMouseOver={() => trigger === 'hover' && setIsTooltipVisible(true)}
      onFocus={() => trigger === 'hover' && setIsTooltipVisible(true)}
      onMouseLeave={() => trigger === 'hover' && setIsTooltipVisible(false)}
    >
      {children}
      <TooltipStyled isVisible={isTooltipVisible} title={title}>
        {title}
      </TooltipStyled>
    </TooltipContainer>
  );
});

Tooltip.defaultProps = {
  position: 'top',
  trigger: 'hover',
};

export default Tooltip;

标签: javascriptreactjstypescript

解决方案


推荐阅读