键入 React 组件工厂函数

Posted

技术标签:

【中文标题】键入 React 组件工厂函数【英文标题】:Typing a React Component Factory Function 【发布时间】: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>>;

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


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

【问题讨论】:

【参考方案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" ] />;

【讨论】:

以上是关于键入 React 组件工厂函数的主要内容,如果未能解决你的问题,请参考以下文章

React系列--组件Component

将组件作为道具传递时在 Flow 中键入 React 组件

强烈键入 react-redux 与 typescript 连接

键入 React Router 路由器组件?使困惑

使用 react-router-dom 在组件基础上键入 location.state 属性

如何在带有 TypeScript 的 React-Native 中使用 styled-component 键入无状态功能组件?