Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

165
Views
Typing a React component that clones its children to add extra props in TypeScript

Assuming you have following component that accepts one or more child JSX.Elements and passes extra callback to their props when they are rendered by using React.cloneElement(child, { onCancel: () => {} }.

Component in question (excerpt):

interface XComponentProps {
    onCancel: (index: number) => void;
}

class XComponent extends React.Component<XComponentProps> {
    render() {
        const { onCancel } = this.props;
        const children = typeof this.props.children === 'function' ?
            React.cloneElement(this.props.children, { onCancel: () => onCancel() }) :
            this.props.children.map((child, idx) => (
                React.cloneElement(child, { onCancel: () => onCancel(idx) })
            ));
        return <div>{children}</div>;
    }
}

Component in question in action (excerpt):

interface UserComponentProps { caption: string }
const UserComponent = (props: UserComponentProps) => (
    <button onClick={props.onClose}>{props.caption || "close"}</button>
);

ReactDOM.render(
    <XComponent onCancel={handleCancel}>
        <UserComponent />
        <UserComponent />
        <UserComponent />
    </XComponent>
);

Right now TSC is complaining that UserComponent does not have onCancel in its props' interface definition, which indeed does not. One easiest fix is to manually define onCancel to UserComponentProps interface.

However, I want to fix it without modifying child node's prop definition so that the component can accept arbitrary set of React elements. In such scenario, is there a way to define typings of returning elements that has extra implicit props passed at the XComponent (parent) level?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

It is not possible. There is no way to know statically what props UserComponent receives from parent XComponent in your ReactDOM.render context.

If you want a type safe solution, use children as functions:

Here is XComponent definition

interface XComponentProps {
    onCancel: (index: number) => void;
    childrenAsFunction: (props: { onCancel: (index: number) => void }) => JSX.Element;
}

class XComponent extends React.Component<XComponentProps> {
    render() {
        const { onCancel } = this.props;
        return <div>{childrenAsFunction({ onCancel })}</div>;
    }
}

Now you can use it to render your UserComponents

<XComponent onCancel={handleCancel} childrenAsFunction={props => 
  <span>
    <UserComponent {...props} />
    <UserComponent {...props} />
  </span>
} />

This will work nicely, I use this pattern often with no hassle. You can refactor XComponentProps to type the childrenAsFunction prop with the relevant part (the onCancel function here).

over 4 years ago · Santiago Trujillo Report

0

I know this has been solved, but another solution is to restrict the type of children that can be passed. Limits the functionality of the wrapper, but could be what you want.

So if you kept your original example:

interface XComponentProps {
   onCancel: (index: number) => void;
   children: ReactElement | ReactElement[]
}

class XComponent extends React.Component<XComponentProps> {
    render() {
        const { onCancel } = this.props;
        const children = !Array.isArray(this.props.children) ?
            React.cloneElement(this.props.children, { onCancel: () => onCancel() }) :
            this.props.children.map((child, idx) => (
                React.cloneElement(child, { onCancel: () => onCancel(idx) })
            ));
        return <div>{children}</div>;
    }
}

interface UserComponentProps { caption: string }
const UserComponent: React.FC = (props: UserComponentProps) => (
    <button onClick={props.onClose}>{props.caption || "close"}</button>
);

ReactDOM.render(
    <XComponent onCancel={handleCancel}>
        <UserComponent />
        <UserComponent />
        <UserComponent />
    </XComponent>
);
over 4 years ago · Santiago Trujillo Report

0

You can pass children as a function, even in JSX. This way you will get proper typing all the way. UserComponents props interface should extend ChildProps.

interface ChildProps {
    onCancel: (index: number) => void;
}

interface XComponentProps {
    onCancel: (index: number) => void;
    children: (props: ChildProps) => React.ReactElement<any>;
}

class XComponent extends React.Component<XComponentProps> {
    render() {
        const { onCancel } = this.props;
        return children({ onCancel })};
    }
}


<XComponent onCancel={handleCancel}>
    { props => <UserComponent {...props} /> } 
</XComponent>
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!