用注入的道具来反应打字稿问题

时间:2020-09-30 18:53:04

标签: javascript reactjs typescript

如何避免对通过React.children.map注入到我直接在打字稿中呈现的组件的道具进行类型检查?

type ContainerProps = {
    children: JSX.Element[];
};
export const Container: React.FC<ContainerProps> = ({ children }) => {
    const [isOpen, setIsOpen] = useState<boolean>(false);

    return (
        <React.Fragment>
            {React.Children.map(children, child =>
                React.cloneElement(child, {
                    isOpen,
                    setIsOpen
                })
            )}
        </React.Fragment>
    );
};
type ClickProps = {
    children: React.ReactNode;
    isOpen: boolean;
    setIsOpen: (boolean) => void;
};
export const Click: React.FC<ClickProps> = ({ children, isOpen, setIsOpen }) => {
    return (
        <div onClick={() => setIsOpen(!isOpen)}>
            {children}
        </div>
    );
};

在这种情况下,当我调用以下代码时,由于未传递isOpensetIsOpen道具,因此出现以下错误。我如何在Click组件内具有这些道具的类型安全性?直接调用click组件时不需要传递它们吗?

<Container>
    <Click>
        <h1>Test</h1>
    </Click>
</Container>

ERROR
Type '{ children: Element; }' is missing the following properties from type 'ClickProps': isOpen, setIsOpents(2739)

1 个答案:

答案 0 :(得分:1)

如何在Click组件内部具有这些道具的类型安全性,而在直接调用click组件时无需传递它们呢?

这里的问题是当您这样做时:

    <Click>
        <h1>Test</h1>
    </Click>

您实际上是在渲染该组件,将其转换为JSX片段。稍后将其克隆,但这对于此初始渲染无关紧要。而且此组件具有一些必需的道具:isOpensetIsOpen

这就像调用缺少参数的函数一样。调用无效。

我认为使用此设置的最佳方法是使道具成为可选,然后除非提供了道具,否则就保释。

type ClickProps = {
    children: React.ReactNode;
    isOpen?: boolean;
    setIsOpen?: (isOpen: boolean) => void;
};
export const Click: React.FC<ClickProps> = ({ children, isOpen, setIsOpen }) => {
    if (isOpen === undefined || setIsOpen === undefined) return null
    return (
        <div onClick={() => setIsOpen(!isOpen)}>
            {children}
        </div>
    );
};

这样,在没有道具的情况下渲染组件是有效的调用。

Playground


不过,我不太确定如何使用React.cloneElement获得类型安全。将子级转换为JSX.Element[]后,打字稿将不再知道来自哪个原始组件,因此我不确定它如何知道要执行哪些道具。

我不确定您要在这里做什么,但是我会在这里重新考虑您的整体策略,看看您是否可以不用React.cloneElement来做到这一点。