【问题标题】:How to type ReactNode that may have props?如何键入可能有道具的 ReactNode?
【发布时间】:2021-05-03 23:23:54
【问题描述】:

我已经为此苦苦挣扎了几个小时,但没有运气。似乎也找不到任何其他有帮助的 stackoverflow 问题。基本上,我有一个组件需要两个子节点,如下所示:

<SharedTwoColumns
  outer={{ className: "mt4 mb4" }}
  gap={<div className="h4 w4" />}
>
  <div className={isMobile ? "" : "pa3"}>Left Column</div> // first child
  <div className={isMobile ? "" : "pa3"}>Right Column</div> // second child
</SharedTwoColumns>    

我正在尝试键入“左列”和“右列”子项,以表明它们可能都有道具,但不一定。到目前为止我所拥有的是:

const SharedTwoColumns = ({
  outer: { className: ocn, ...outer },
  children,
  gap: {
    props: { className: gcn, ...gapProps }
  }
}: {
  outer: { [x: string]: unknown; className: string };
  children: ReactNode;
  gap: { props: { [x: string]: unknown; className: string } };
}) => {

...

  const [leftColumn, rightColumn]: ReactNode[] = Children.toArray(children);
  const {
    props: { className: lcn, children: leftColumnChildren, ...leftColumnProps }
  }: ReactNode = leftColumn || {}; // TS error happens here when I hover over 'props'

但是,这给了我打字稿错误:

Property 'props' does not exist on type 'boolean | ReactChild | ReactFragment | ReactPortal | null'.

any

在从leftColumn 解构道具时,是否有人对我如何正确输入此内容有任何想法?

【问题讨论】:

    标签: reactjs typescript react-typescript


    【解决方案1】:

    如果我理解正确,您需要为您的孩子使用ReactElement 类型,类似这样:

    import React, { ReactElement } from "react";
    
    interface LeftProps {
      left: string;
    }
    const Left = (props: LeftProps) => null;
    
    interface RightProps {
      right: string;
    }
    const Right = (props: RightProps) => null;
    
    interface LayoutProps {
      children: [ReactElement<LeftProps>, ReactElement<RightProps>];
    }
    
    function Layout({ children }: LayoutProps) {
      // You may use React.children.toArray here but it will force you to typecast
      // in some cases (like this one with tuple)
      const left = children[0].props.left;
      const right = children[1].props.right;
    
      return (
        <div>
          Right: {right} Left: {left}
        </div>
      );
    }
    
    export default function App() {
      return (
        <Layout>
          <Left left="left" />
          <Right right="right" />
        </Layout>
      );
    }
    

    【讨论】:

    • 谢谢!关键是我没有 React.children.toArray 类型转换。不知道它正在这样做,但它正在搞砸一切。结合使用 JSX.Element 完成了我需要它做的事情
    • @DannyY 在不使用 React.children.toArray 时,请注意片段和其他间接方式将节点作为子节点传递,它可能会破坏。
    【解决方案2】:

    不确定这是否能回答您的问题,但您可以创建一个扩展 ReactNode 类的接口。 例如

    interface MyNode extends ReactNode {
      // ... your custom props here
    }
    

    这样,我相信你可以使用你的自定义界面来输入你的列,在某种程度上它们拥有 ReactNode 的所有原生道具以及你的自定义道具

    【讨论】:

    • 感谢您的回复。这对我来说有些道理,但我不确定这到底是如何工作的。就我而言,classNamechildren 不是本机 ReactNode 道具,所以这不应该起作用吗?至于...leftColumnProps,有没有办法使用您建议的扩展界面来输入所有其他可能的道具?
    猜你喜欢
    • 2021-09-04
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    相关资源
    最近更新 更多