Specify specific props and accept general HTML props in Typescript React App
We can have a look at how div
props are defined:
interface IntrinsicElements { div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;}
If we use React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
as the base type we will have all properties of div
. Since DetailedHTMLProps
just adds ref
to React.HTMLAttributes<HTMLDivElement>
we can use just this as the base interface to get all div
properties:
interface WrapperProps extends React.HTMLAttributes<HTMLDivElement> { callback?: Function}export class Wrapper extends React.Component<WrapperProps>{ render() { const { callback, children, ...rest } = this.props; return <div {...rest}> {children} </div>; }}export const Test = () => { return <Wrapper className="test">Hi there</Wrapper> // works now}
JSX.IntrinsicElements has this info, e.g.
const FooButton: React.FC<JSX.IntrinsicElements['button']> = props => ( <button {...props} className={`foo ${props.className}`} />)// alternative...const FooButton: React.FC<React.PropsWithoutRef< JSX.IntrinsicElements['button']>> = props => <button {...props} className={`foo ${props.className}`} />
discovered this in the react-typescript-cheatsheet project.
A co-worker of mine figured it out. Sharing here for broader visibility:
interface ComponentPropTypes = { elementName?: keyof JSX.IntrinsicElements; // list of all native DOM components ...}// Function componentfunction Component({ elementName: Component = 'div', ...rest, // React.HTMLAttributes<HTMLOrSVGElement>) provides all possible native DOM attributes}: ComponentPropTypes & React.HTMLAttributes<HTMLOrSVGElement>)): JSX.Element { return <Component {...rest} />;}// Class componentclass Component extends React.Component<ComponentPropTypes & React.HTMLAttributes<HTMLOrSVGElement>> { render() { const { elementName: Component, ...rest, } = this.props; return <Component {...rest} /> }}