javascript - Typescript React `isValidElement` typ-vakt fungerar inte som förväntat


Jag har en tooltip-komponent implementerad så här (jag har förenklat den), som kan användas på två olika sätt genom att skicka ett värde till tooltip-prop, antingen blir det ett JSX-element eller en callback-funktion som slutligen returnerar ett ReactElement:

import { isValidElement, ReactNode, useCallback, useState } from 'react';
import { Portal } from 'react-portal';

interface ChildrenProps {
    onHide: () => void;
    onShow: () => void;
}

type TooltipCallback = (onHide: () => void) => ReactNode;

export interface Props {
    tooltip: ReactNode | TooltipCallback;
    children: (props: ChildrenProps) => ReactNode;
}

export function Tooltip({ children, tooltip }: Props) {
    const [show, setShow] = useState(false);

    const onHide = useCallback(() => {
        setShow(false);
    }, []);

    const onShow = useCallback(() => {
        setShow(true);
    }, []);

    return (
        <>
            {children({ onHide, onShow })}
            <Portal>
                {show && tooltip !== null && tooltip !== undefined && (
                    <div className="tooltip">
                        {/* TS complains here */}
                        {isValidElement(tooltip) ? tooltip : tooltip(onHide)}
                    </div>
                )}
            </Portal>
        </>
    );
}

Användning genom att skicka en callback-funktion till tooltip:

<Tooltip
    tooltip={(onHide) => (
        <div>
            <span>
                In this tooltip, the only way to close it is by clicking the close button in the tooltip
            </span>
            <button onClick={onHide}>close</button>
        </div>
    )}
>
    {({ onShow }) => <span onMouseOver={onShow}>Some text that triggers tooltip</span>}
</Tooltip>

Användning genom att skicka ett ReactElement till tooltip:

<Tooltip
    tooltip={
        <span>This is a tooltip that will be closed when goes away when your mouse leaves</span>
    }
>
    {({ onShow, onHide }) => (
        <span onMouseLeave={onHide} onMouseOver={onShow}>
            Some text that triggers tooltip
        </span>
    )}
</Tooltip>;

Men TypeScript klagar på det:

This expression is not callable.
  Not all constituents of type 'string | number | boolean | {} | ReactNodeArray | TooltipCallback' are callable.
    Type 'string' has no call signatures.ts(2349)

Men jag antog att eftersom jag har kontrollen isValidElement(tooltip), så är det garanterat att typen av tooltip inte är string | number | {} | ReactNodeArray när man försöker rendera tooltipen med callback-funktionen i else-satsen.

Hur fixar jag detta TS-fel?

Relaterade artiklar