DEV Community

Discussion on: Introducing The Recursive `Pipe` and `Compose` Types

Collapse
 
ackvf profile image
Vítězslav Ackermann Ferko • Edited

Hi, at first I would like to say that I like your approach the most of all I've seen.

My question, coming from React, is:
Would it be possible to compose functions in a way, that any extra incoming arguments are passed along with current's hoc outgoing arguments to next hoc, and that any extra arguments of the wrapped function that are not satisfied by any hoc are also exposed in the outer interface?

In React it makes sense as higher order components/functions usually don't represent a chain of actions on a single value, but instead add some functionality and add additional props to the underlying consumer component. Though, it's all in a single object called props.

It's somewhat difficult to express clearly, so here's the idea:

interface InnerProps { c: number, d: number }
interface H1in { a: number }
interface H1out { b: number }
interface H2in { b: number }
interface H2out { c: number }

declare const WrappedComponent: (props: InnerProps) => any // React component
declare const H1: (props: H1in) => H1out & H1in // also must pass rest properties ({a, ...rest}) => ({b: a + 10, ...rest})
declare const H2: (props: H2in) => H2out & H2in // ...rest properties

const OuterComponent: (props: OuterProps) => any = pipe(H1, H2)(WrappedComponent)
/*
interface OuterProps { 
  a: number // from H1
  d: number // WrappedComponent own props that are not satisfied by any available HOC
  // b, c are not exposed as they are satisfied from the chain
}
*/

A real life usage could be

interface MyComponentProps { giveMeThisProp: any }
declare const MyComponent: React.FC<MyComponentProps & Theme & Query>

pipe(
  withSettings,
  withApolloQuery(query),
  withTheme
)(
  MyComponent
)

Where the MyComponent doesn't really care about what withSettings returns, but withApolloQuery needs it. MyComponent then cares about the result, theme and the consumer should provide the additional required prop: <MyComponent giveMeThisProp={true} />