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

352
Views
How can I preserve generics on a React higher-order component?

Let's say I want to use the React higher-order component pattern to transform a subset of my props before they hit my component:

type UpstreamProps<X> = {
    foo?: number
    bar?: string
    baz:  X
}

type DownstreamProps<X> = {
    foo: number
    bar: string
    baz: X
    bix: string
}

function transform<X>(props: UpstreamProps<X>): DownstreamProps<X> {
    return {
        ...props,
        foo: props.foo || 0,
        bar: props.bar || '(unknown)',
        bix: `${props.foo}-${props.bar}-bix`
    }
}

At the widget definition, I want to use downstream (strict) props:

function Parent<X>(props: DownstreamProps<X> & {formatter: (x: X) => string}) {
    return (
        <>
            foo = {props.foo}
            bar = {props.bar}
            baz = {props.formatter(props.baz)}
            bix = {props.bix}
        </>
    )
}

At the call site, I should be able to pass in upstream (optional) props:

<WrappedParent<number>
    baz={22}
    formatter={(x: number) => `my number squared is ${Math.pow(x, 2)}`}
/>

This is as close as I've gotten to writing the higher-order component, but I can't get it to play well with the generics on the Parent/WrappedParent:

function withUpstreamProps<X, OtherProps>(
    WrappedComponent: React.ComponentType<DownstreamProps<X> & OtherProps>
) {
    return function({foo, bar, baz, ...otherProps}: UpstreamProps<X> & OtherProps) {
        return (
            <WrappedComponent
                {...otherProps}
                {...transform({foo, bar, baz})}
            />
        )
    }
}

export default withUpstreamProps(Parent) // doesn't keep generics

There are two requirements here that are difficult to reconcile:

  1. withUpstreamProps(someRandomComponent) should be an error. withUpstreamProps should only accept a valid component as an argument; i.e., one that accepts a superset of DownstreamProps<X>.
  2. The emitted WrappedParent should be parameterized by one generic parameter; e.g. WrappedParent<number>.

How can I write and/or use my higher-order component wrapper to meet these requirements?

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

Would something like that work for your case?:

type Wrapped<X, Other> = React.ComponentType<Output<X> & Other>

function withUpstreamProps<C extends Wrapped<any, any>>(
    WrappedComponent: C
) {
    return function<X, OtherProps>({foo, bar, baz, ...otherProps}: Input<X> & OtherProps) {
        return (
            <WrappedComponent
                {...otherProps}
                {...transform({foo, bar, baz})}
            />
        )
    }
}
about 4 years ago · Juan Pablo Isaza Report

0

If you want to pass the generic type to the resulting component, the function returned from the HOC should be generic and take the X type as an argument and then pass it to WrappedComponent.

function withUpstreamProps(
  WrappedComponent: React.FunctionalComponent
) {
  return function <X, OtherProps>({
    foo,
    bar,
    baz,
    ...otherProps
  }: UpstreamProps<X> & OtherProps) {
    return (
      <WrappedComponent<X> {...otherProps} {...transform({ foo, bar, baz })} />
    );
  };
}

The OtherProps type should be passed too, so the WrappedParent would recognize the formatter function.

You should also assign a type for the formatter function when using the resulting component (WrappedParent)

If my answer was helpful an upvote would be appreciated.

about 4 years ago · Juan Pablo Isaza 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!