【问题标题】:Typing a React Component Factory Function键入 React 组件工厂函数
【发布时间】:2021-09-24 14:28:03
【问题描述】:

给定类型

type EnumerableComponentFactory = <C, I>(config: {
  Container: React.ComponentType<C>;
  Item: React.ComponentType<I>;
}) => React.FC<{ items: I[] }>;

使用以下实现

const Enumerable: EnumerableComponentFactory =
  ({ Container, Item }) =>
  ({ items }) =>
    (
      <Container>
        {items.map((props, index) => (
          <Item key={index} {...props} />
        ))}
      </Container>
    );

和预期用途

const UnorderedList = Enumerable({
  Container: ({ children }) => <ul>{children}</ul>,
  Item: ({ title }: { title: string }) => <li>{title}</li>,
});

<UnorderedList items=[{title: "Something"}] />

我观察到以下 TypeScript 错误

Type '{ children: Element[]; }' is not assignable to type 'C'.
  'C' could be instantiated with an arbitrary type which could be unrelated to '{ children: Element[]; }'.ts(2322)

这引出了我的问题:我需要设置哪些类型约束来解决此错误?

我尝试将类型更改如下:

type EnumerableComponentFactory = <C extends { children?: Element[] }, I>(config: {
  Container: ComponentType<C>;
  Item: ComponentType<I>;
}) => (props: { items: I[] }) => ReturnType<FC<I>>;

但这会产生一个更加神秘的错误消息,为了简洁起见,我将省略它。


附:该函数本身实际上完全符合预期。只是编译器出错了。

【问题讨论】:

    标签: reactjs typescript factory type-constraints tsx


    【解决方案1】:

    我能够更改您的代码以使其正常工作,同时还接受其他要传递给容器的道具:

    type EnumerableComponentFactory = <C, I>(config: {
        Container: React.ComponentType<C & { children: React.ReactNode[] }>;
        Item: React.ComponentType<I>;
    }) => React.ComponentType<C & { items: I[] }>;
    
    const Enumerable: EnumerableComponentFactory = ({ Container, Item }) => (
        props
    ) => (
        <Container {...props}>
            {props.items.map((props, index) => (
                <Item key={index} {...props} />
            ))}
        </Container>
    );
    

    这允许例如这个:

    const ContainerWithBorder: React.ComponentType<{ color: string }> = (props) => (
        <div style={{ border: `2px solid ${props.color}` }}>
            <ul>{props.children}</ul>
        </div>
    );
    
    const ComplexList = Enumerable({
        Container: ContainerWithBorder,
        Item: ({ title }: { title: string }) => <li>{title}</li>
    });
    
    <ComplexList items={[{ title: "Something" }]} color="red" />
    

    ComplexList 组件带有 color 属性的打字/智能感知。

    可以在here 找到带有原始示例和ComplexList 示例的游乐场。

    【讨论】:

      【解决方案2】:

      是否需要保留C泛型参数?

      import React, { FC, ComponentType, PropsWithChildren } from "react";
      
      type EnumerableComponentFactory = <I>(config: {
        // or Container: FC<{ children: JSX.Element[] }>;
        Container: FC<PropsWithChildren<object>>;
        Item: ComponentType<I>;
      }) => FC<{ items: I[] }>;
      
      const Enumerable: EnumerableComponentFactory =
        ({ Container, Item }) =>
        ({ items }) =>
          (
            <Container>
              {items.map((props, index) => (
                <Item key={index} {...props} />
              ))}
            </Container>
          );
      
      const UnorderedList = Enumerable({
        Container: ({ children }) => <ul>{children}</ul>,
        Item: ({ title }: { title: string }) => <li>{title}</li>,
      });
      
      const result = <UnorderedList items={[{ title: "Something" }]} />;
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-04
        • 2017-06-08
        相关资源
        最近更新 更多