英文:
How can Typescript correctly infer generics in react component props?
问题
以下是您要翻译的部分:
只是为了上下文,我正在创建一个组件,如果子元素溢出,它会显示一个工具提示。 children 属性是一个渲染函数,因此调用此组件的人可以将 RefObject 分配给子组件的任何 ref 属性(例如:ref、itemRef、inputRef 等),以及应该调用的事件 onMouseEnter。
import { TooltipProps } from '@mui/material';
export type OverflowTooltipProps = Omit<TooltipProps, 'children'> & {
    children: <RefElem extends HTMLElement>(
        ref: RefObject<RefElem>,
        onMouseEnter: () => void
    ) => ReactElement;
};
const OverflowTooltip = <RefElem extends HTMLElement>(props: OverflowTooltipProps) => {
    const { children, disableHoverListener, ...other } = props;
    const [overflowing, setOverflowing] = useState(false);
    const childrenRef = useRef<RefElem>(null);
    const testIfOverflowing = () => {
        const scrollWidth = childrenRef.current?.scrollWidth;
        const clientWidth = childrenRef.current?.clientWidth;
        if (scrollWidth && clientWidth) {
            setOverflowing(scrollWidth > clientWidth);
        }
    };
    useEffect(() => {
        testIfOverflowing();
        window.addEventListener('resize', testIfOverflowing);
        return () => window.removeEventListener('resize', testIfOverflowing);
    }, [children]);
    return (
        <Tooltip disableHoverListener={disableHoverListener || !overflowing} {...other}>
            {children<RefElem>(childrenRef, testIfOverflowing)}
        </Tooltip>
    );
};
这是一个(简化的)用例:
<OverflowTooltip title={attachment.file.name}>
    {(ref, onMouseEnter) => (
        <Chip ref={ref} label={attachment.file.name} onMouseEnter={onMouseEnter} />
    )}
</OverflowTooltip>
但是,我收到以下错误:
我做错了什么?这不应该根据使用的泛型正确推断吗?
英文:
Just for context, I'm creating a component that shows a Tooltip if the child element is overflowing. children prop is a render function so whoever calls this component can assign the RefObject to whichever ref prop of the child component it wants (i.e.: ref, itemRef, inputRef,..), as well as the event that should be called onMouseEnter.
import { TooltipProps } from '@mui/material';
export type OverflowTooltipProps = Omit<TooltipProps, 'children'> & {
	children: <RefElem extends HTMLElement>(
		ref: RefObject<RefElem>,
		onMouseEnter: () => void
	) => ReactElement;
};
const OverflowTooltip = <RefElem extends HTMLElement>(props: OverflowTooltipProps) => {
	const { children, disableHoverListener, ...other } = props;
	const [overflowing, setOverflowing] = useState(false);
	const childrenRef = useRef<RefElem>(null);
	const testIfOverflowing = () => {
		const scrollWidth = childrenRef.current?.scrollWidth;
		const clientWidth = childrenRef.current?.clientWidth;
		if (scrollWidth && clientWidth) {
			setOverflowing(scrollWidth > clientWidth);
		}
	};
	useEffect(() => {
		testIfOverflowing();
		window.addEventListener('resize', testIfOverflowing);
		return () => window.removeEventListener('resize', testIfOverflowing);
	}, [children]);
	return (
		<Tooltip disableHoverListener={disableHoverListener || !overflowing} {...other}>
			{children<RefElem>(childrenRef, testIfOverflowing)}
		</Tooltip>
	);
};
This is a (simplified) use case:
<OverflowTooltip title={attachment.file.name}>
	{(ref, onMouseEnter) => (
		<Chip ref={ref} label={attachment.file.name} onMouseEnter={onMouseEnter} />
	)}
</OverflowTooltip>
However, I get the following error:
What am I doing wrong? Shouldn't this be inferred correctly because of the generics being used?
答案1
得分: 2
这是您要翻译的代码部分:
import { Chip, Tooltip, TooltipProps } from "@mui/material";
import { ReactElement, RefObject, useEffect, useRef, useState } from "react";
export type OverflowTooltipProps<RefElem extends HTMLElement> = Omit<
  TooltipProps,
  "children"
> & {
  children: (ref: RefObject<RefElem>, onMouseEnter: () => void) => ReactElement;
};
const OverflowTooltip = <RefElem extends HTMLElement>(
  props: OverflowTooltipProps<RefElem>
) => {
  const { children, disableHoverListener, ...other } = props;
  const [overflowing, setOverflowing] = useState(false);
  const childrenRef = useRef<RefElem>(null);
  const testIfOverflowing = () => {
    const scrollWidth = childrenRef.current?.scrollWidth;
    const clientWidth = childrenRef.current?.clientWidth;
    if (scrollWidth && clientWidth) {
      setOverflowing(scrollWidth > clientWidth);
    }
  };
  useEffect(() => {
    testIfOverflowing();
    window.addEventListener("resize", testIfOverflowing);
    return () => window.removeEventListener("resize", testIfOverflowing);
  }, [children]);
  return (
    <Tooltip
      disableHoverListener={disableHoverListener || !overflowing}
      {...other}
    >
      {children(childrenRef, testIfOverflowing)}
    </Tooltip>
  );
};
const attachment = {
  file: {
    name: "test",
  },
};
const App = () => {
  <OverflowTooltip<HTMLDivElement> title={attachment.file.name}>
    {(ref, onMouseEnter) => (
      <Chip
        ref={ref}
        label={attachment.file.name}
        onMouseEnter={onMouseEnter}
      />
    )}
  </OverflowTooltip>;
};
如果您需要进一步的帮助,请告诉我。
英文:
You actually have to pass generic into to type also. Here you have working solution:
import { Chip, Tooltip, TooltipProps } from "@mui/material";
import { ReactElement, RefObject, useEffect, useRef, useState } from "react";
export type OverflowTooltipProps<RefElem extends HTMLElement> = Omit<
  TooltipProps,
  "children"
> & {
  children: (ref: RefObject<RefElem>, onMouseEnter: () => void) => ReactElement;
};
const OverflowTooltip = <RefElem extends HTMLElement>(
  props: OverflowTooltipProps<RefElem>
) => {
  const { children, disableHoverListener, ...other } = props;
  const [overflowing, setOverflowing] = useState(false);
  const childrenRef = useRef<RefElem>(null);
  const testIfOverflowing = () => {
    const scrollWidth = childrenRef.current?.scrollWidth;
    const clientWidth = childrenRef.current?.clientWidth;
    if (scrollWidth && clientWidth) {
      setOverflowing(scrollWidth > clientWidth);
    }
  };
  useEffect(() => {
    testIfOverflowing();
    window.addEventListener("resize", testIfOverflowing);
    return () => window.removeEventListener("resize", testIfOverflowing);
  }, [children]);
  return (
    <Tooltip
      disableHoverListener={disableHoverListener || !overflowing}
      {...other}
    >
      {children(childrenRef, testIfOverflowing)}
    </Tooltip>
  );
};
const attachment = {
  file: {
    name: "test",
  },
};
const App = () => {
  <OverflowTooltip<HTMLDivElement> title={attachment.file.name}>
    {(ref, onMouseEnter) => (
      <Chip
        ref={ref}
        label={attachment.file.name}
        onMouseEnter={onMouseEnter}
      />
    )}
  </OverflowTooltip>;
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论