I am using recompose in React, in particular its compose
function which has a signature of
function compose<TInner, TOutter>(
...functions: Function[]
): ComponentEnhancer<TInner, TOutter>;
interface ComponentEnhancer<TInner, TOutter> {
(component: Component<TInner>): ComponentClass<TOutter>;
}
where I am passing in some React higher order components. I defined my TInner
and TOuter
types as interfaces that describe what I need in order for my HoCs to function:
interface IOuterProps {
somethingYouGiveMe: string;
}
interface IInnerProps {
somethingIGiveBack: number;
}
const myEnhancer = compose<IInnerProps, IOuterProps>(myHoC, myOtherHoc);
(as a silly example for demonstration). But the problem is, my components have more props than that, the HoC that compose generates needs to take those extra props and pass them through, for example:
interface IMyComponentProps {
somethingYouGiveMe: string;
somethingElse: string;
}
Because of this, I can't do const MyEnhancedComponent = myEnhancer(MyComponent)
, as the compiler will complain that MyEnhancedComponent
does not have somethingElse
as a prop.
I found two work arounds, neither I am happy with. So curious what more experienced TypeScript devs would do.
Work Around #1: Introduce a function
By introducing a function, I can use generics and express to the compiler what I am doing
function myEnhancer<TInnerProps extends IInnerProps, TOuterProps extends IOuterProps>(Component: React.ComponentType<TInnerProps>) {
return compose<TInnerProps, TOuterProps>(mYHoC, myOtherHoc)(Component);
}
I really dislike this, introducing a function that will create multiple copies of the enhancer, just to get at generics? Seems wrong to me.
Work Around #2: use [key:string]: any
I can instead change my interfaces to be
interface IOutterProps {
somethingYouGiveMe: string;
[key: string]: any;
}
interface IInnerProps extends IOuterProps {
somethingIGiveBack: number;
}
I am basically using [key:string]: any
as a poor man's extends IOutterProps
. As in, I need you to give me these props, and if you give me extras then I don't really care about those.
This allows me to use myEnhancer
where ever I have components that meet the requirements, avoids the added function, and feels better than workaround #1. But also it feels wrong to have to add [key: string]: any
.