I am writing the typings for an existing UI library which has a Base component which takes in Element
as a string and does <Element {...props}
What is the correct way to type it?
I have tried writing a generic type with
type AllTypes = HTMLProps<HTMLDivElement> | HTMLProps<HTMLInputElement> // ... And other HTML element types
type BaseTypes <T extends AllTypes> = {
Element: string;
props: T;
className?: string;
baseClassName?: string;
}
export const BaseComponent = <T extends AllTypes>({
Element = "div",
baseClassName,
className,
...props
}: BaseTypes<T> ) => {
const classNames = [];
if (baseClassName) {
classNames.push(baseClassName);
}
if (className) {
classNames.push(className);
}
return (
<Element
className={classNames.join(' ')}
{...props }
/>
)
}
and on the other side
type newType = {
Element: string;
props: HTMLProps<HTMLInputElement>,
className?: string;
baseClassName?:string;
}
const InputField = (props: newType): ReactElement => {
return (
<BaseComponent<HTMLProps<HTMLInputElement>>
Element="input"
baseClassName="ff-input"
{...props}
/>
);
};
export default InputField;
I am getting errors like cannot assign {className:string}
to IntrinsicAttributes.
I would like to know the correct way to type the BaseComponent such that the props types are decided based on the Element value. Any suggestion would be appreciated.
You can't use just a plain string as Element
with JSX. If you want to use a string you could swap to doing this...
React.createElement(Element, { ...props, className: classNames.join(' ') }, null);
Alternatively you can amend the type of Element to be ElementType<any>
, for example...
import * as React from 'react';
import { HTMLProps, ReactElement, ElementType } from 'react';
export type BaseProps = {
Element: ElementType<any>;
className?: string;
baseClassName?: string;
}
export const BaseComponent = <T extends {}>({
Element = "div",
baseClassName,
className,
...props
}: T & BaseProps) => {
const classNames = [];
if (baseClassName) {
classNames.push(baseClassName);
}
if (className) {
classNames.push(className);
}
return <Element { ...{...props, className: classNames.join(' ') } } />;
}
const InputField = (props: HTMLProps<HTMLInputElement>): ReactElement => {
return (
<BaseComponent<HTMLProps<HTMLInputElement>>
Element="input"
baseClassName="ff-input"
{...props}
/>
);
};
export default InputField;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.