Ввод функции React Component Factory

Учитывая тип

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>>;

но это приводит к еще более загадочному сообщению об ошибке, которое я буду опускать для краткости.


P.S. Сама функция на самом деле делает именно то, что ожидается. Это просто компилятор, который спотыкается.


person t6d    schedule 15.07.2021    source источник


Ответы (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" }]} />;

person captain-yossarian    schedule 18.07.2021

Я смог изменить ваш код, чтобы он работал, а также принять другие реквизиты для передачи в контейнер:

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.

Площадку с оригинальным и ComplexList примером можно найти здесь.

person Kelvin Schoofs    schedule 23.07.2021