I have a React Wrapper Component, that accepts some props, but forwards all others to the child component (especially relevent for native props like className, id, etc.).
Typescript complains, however, when I pass native props. See error message:
TS2339: Property 'className' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes< Wrapper > & Readonly< { children?: ReactNode; }> & Readonly< WrapperProps>'.
How can I get a component with specific props that also accepts native props (without accepting any props and giving up on type checking)?
My code looks like this:
interface WrapperProps extends JSX.IntrinsicAttributes { 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> }
FYI: I found a similar question here, but the answer basically gives up type checking, which I want to avoid: Link to SO-Question
By invoking them between the opening and closing tags of a JSX element, you can use React children for entering data into a component. The React children prop is an important concept for creating reusable components because it allows components to be constructed together.
To pass an object as props to a component in React TypeScript: Define an interface for the type of the object. Pass an object of the specified type to the child component, e.g. <Employee {... obj} /> .
To pass a function as props in React TypeScript: Define a type for the function property in the component's interface. Define the function in the parent component. Pass the function as a prop to the child component.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With