Динамическое создание элемента React в Typescript

#reactjs #typescript

Вопрос:

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

 type ElementProps<Tag extends keyof JSX.IntrinsicElements> =
  JSX.IntrinsicElements[Tag];

type Props = {
  tagName?: React.ComponentType | keyof JSX.IntrinsicElements;
};

const Editable: React.FC<Props> = ({
  tagName = 'div',
  ...props
}) => {
  const htmlEl = useRef(null);

  const elementProps: ElementProps<typeof tagName> = {
    ...props,
    ref: htmlEl,
  };

  return createElement(tagName, elementProps, children);
};
 

Я получаю эту ошибку

 Type 'keyof IntrinsicElements | ComponentType<{}>' does not satisfy the constraint 'keyof IntrinsicElements'.
  Type 'ComponentClass<{}, any>' is not assignable to type 'keyof IntrinsicElements'.
    Type 'ComponentClass<{}, any>' is not assignable to type '"view"'
 

Ответ №1:

Вы были близки.

ElementProps ожидает строку — keyof JSX.IntrinsicElements typeof tagName может ли быть a ComponentType<{} .

Все, что вам нужно сделать, это переместить ограничение типа внутри утилиты типа.

 import React, { useRef, createElement } from "react";

type ElementProps<Tag> =
  Tag extends keyof JSX.IntrinsicElements
  ? JSX.IntrinsicElements[Tag]
  : never

type Props = {
  tagName?: React.ComponentType | keyof JSX.IntrinsicElements;
};

const Editable: React.FC<Props> = ({
  tagName = 'div',
  ...props
}) => {
  const htmlEl = useRef(null);

  const elementProps: ElementProps<typeof tagName> = {
    ...props,
    ref: htmlEl,
  };

  return createElement(tagName, elementProps);
};
 

Игровая площадка

Мне было интересно, смогу ли я получить единственную подробную информацию о теге, переданном в tagname?

Конечно, это возможно.

 import React, { useRef, createElement } from "react";

type ElementProps<Tag> = Tag extends keyof JSX.IntrinsicElements
  ? JSX.IntrinsicElements[Tag]
  : never;

type Values<T> = T[keyof T];

type ObtainHTMLProps<T extends Values<JSX.IntrinsicElements>> =
  T extends React.DetailedHTMLProps<infer Props, HTMLElement> ? Props : never;

type AllowedProps = Values<{
  [Tag in keyof JSX.IntrinsicElements]: {
    tagName: Tag;
  } amp; ObtainHTMLProps<JSX.IntrinsicElements[Tag]>;
}>;  

const Editable: React.FC<AllowedProps> = ({ tagName = "div", ...props }) => {
  const htmlEl = useRef(null);

  const elementProps: ElementProps<typeof tagName> = {
    ...props,
    ref: htmlEl,
  };

  return createElement(tagName, elementProps);
};

const canvas = <Editable tagName="canvas" width={20} /> // ok
const anchor = <Editable tagName="a" href={'www.example.com'} /> // ok

const invalid = <Editable tagName="canvas" href={'www.example.com'} /> // expected error

 

См .раздел Типы реакций node_modules@typesreactindex.d.ts . Вы найдете там IntrinsicElements

введите описание изображения здесь

Имея tagName вы можете легко вывести первый аргумент DetailedHTMLProps . Видеть ObtainHTMLProps .

Теперь вам нужно создать объединение всех разрешенных атрибутов, и это конечное число реквизитов. Видеть AllowedProps .

Комментарии:

1. Это работает, спасибо, мне было интересно, смогу ли я получить единственную подробную информацию о теге, переданном в tagname?

2. Спасибо, спасибо за это. 👍