Я хочу создать MyComponent со свойством «as
», которое позволит ему наследовать свойства компонента as
, чтобы я мог получать типизацию TypeScript.
например
Использование с элементами HTML:
<MyComponent
as = "label"
htmlFor = "caption" /* this should autocomplete from label */
asdf = "" /* this should give error */
className = "test"
>
Test
</MyComponent>
С компонентами React:
<MyComponent
as = {MyGrid}
rows = {4} /* this should autocomplete from MyGrid */
asdf = "" /* this should give error */
>
Test
</MyComponent>
Пока у меня есть это, которое работает как компонент, но, к сожалению, не наследует типы.
import { useRef, forwardRef } from "react";
import type {
PropsWithChildren,
ElementType,
ComponentProps,
ForwardedRef,
ReactElement,
} from "react";
type MyProps<T extends ElementType> =
ComponentProps<T> &
PropsWithChildren &
{ as?: T };
function _MyComponent<T extends ElementType = "div">(
{ as, children, ...props }: MyProps<T>,
ref: ForwardedRef<HTMLElement>,
): ReactElement<T> {
const Comp = as ?? "div";
return (
<Comp {...props} ref = {ref}>
{children}
</Comp>
);
}
const MyComponent = forwardRef(_MyComponent);
export default MyComponent;
Как мне нужно изменить Typescript, чтобы я мог получать предложения по типу?
Я заработал, добавив утверждение типа в вызов frontRef:
export const MyComponent = forwardRef(_MyComponent) as <
T extends ElementType = "div"
>(
props: MyProps<T> & { ref?: React.Ref<Element> }
) => ReactElement | null;
<MyComponent
as = "label"
htmlFor = "caption" // this autocompletes
asdf = "" // this gives error
>
Test
</MyComponent>
const MyGrid = ({ rows }: { rows: number }) => (
<div style = {{ gridTemplateRows: `repeat(${rows}, 1fr)` }}></div>
);
<MyComponent as = {MyGrid} rows = {4}>Test</MyComponent>;
Модифицируем MyProps
, чтобы он работал для элементов HTML.
type MyProps<T extends ElementType> = {
as?: T;
} & ComponentPropsWithoutRef<T>;
Пожалуйста, смотрите обновленный ответ @KernelJames
Кажется, он работает для
MyGrid
, но не для элементов HTML, таких как «метка».