Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify specific props and accept general HTML props in Typescript React App

Tags:

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

like image 371
Sergej Herbert Avatar asked Aug 14 '18 07:08

Sergej Herbert


People also ask

How do you define props in React TypeScript?

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.

How do you pass objects as props in React TypeScript?

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} /> .

How do you pass props in functional component TypeScript?

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.


2 Answers

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 } 
like image 154
Titian Cernicova-Dragomir Avatar answered Sep 22 '22 14:09

Titian Cernicova-Dragomir


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.

like image 42
schpet Avatar answered Sep 21 '22 14:09

schpet