#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. Спасибо, спасибо за это. 👍