首页 > 解决方案 > 用注入的道具反应打字稿问题

问题描述

如何避免对使用 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>
    );
};

在这种情况下,当我调用以下代码时,我会收到以下错误,因为未传入isOpenandsetIsOpen道具。如何在 Click 组件中确保这些道具的类型安全,而在直接调用 click 组件时不需要传入它们?

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

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

标签: javascriptreactjstypescript

解决方案


如何在 Click 组件中确保这些 props 的类型安全,同时在直接调用 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>
    );
};

这样,在没有 props 的情况下渲染组件是一个有效的调用。

操场


不过,我不太确定你是如何获得类型安全的React.cloneElement。一旦您将孩子投射为JSX.Element[]然后打字稿不再知道来自的原始组件,所以我不确定它如何知道要强制执行哪些道具。

我不确定你到底想在这里做什么,但我会在这里重新考虑你的整体策略,看看你是否可以在没有React.cloneElement.


推荐阅读