Reputation: 779
I have a utility function that takes a (now unused) options parameter and returns a higher-order component wrapping function.
How do I properly set types on the component to let users of the wrapped component see the types for the underlying, wrapped component as well as the additional context type from the withAppContext
higher-order component?
type AppContext = {
id: string;
};
const withAppContext = (opts) => {
const hoc = WrappedComponent => {
class WithAppContext extends React.Component<any, any> {
static contextTypes = {
appContext: PropTypes.shape({
id: PropTypes.string,
}),
};
context: AppContext;
render() {
return React.createElement(WrappedComponent, {
...this.props,
...this.context
});
}
}
return WithAppContext;
};
return hoc;
};
When extending just React.Component
(without <any, any>
) I get complaints about IntrinsicAttributes
not containing the props I am passing (i.e. I don't seem to be able to just pass through props to the wrapped component):
error TS2339: Property 'onClick' does not exist on type
'IntrinsicAttributes
& IntrinsicClassAttributes<WithCustomerContext>
& Readonly<{ children?: React...'.
Upvotes: 1
Views: 628
Reputation: 249646
Your hoc
function should be a generic so that properties can be inferred based on usage:
const withAppContext = function (opts) {
function hoc <P>(WrappedComponent: React.StatelessComponent<P>) : React.ComponentClass<P>
function hoc <P, T extends React.Component<P, React.ComponentState>, C extends React.ComponentClass<P>>(WrappedComponent: React.ClassType<P, T, C>) : React.ComponentClass<P>
function hoc <P>(WrappedComponent: any ) : React.ComponentClass<P>
{
class WithAppContext extends React.Component<P> {
context: AppContext;
render() {
return React.createElement(WrappedComponent, Object.assign({}, this.props, this.context));
}
}
return WithAppContext;
};
return hoc;
}
class MyComponent extends React.Component<{ prop: string }>{
}
const MyComponentWithContext = withAppContext({})(MyComponent);
let d = <MyComponentWithContext prop ="" />
let GreeterComponent = function (props: {name: string, greeting: string}){
return <div>{props.greeting} {props.name}!</div>
}
const GreeterComponentContext = withAppContext({})(GreeterComponent);
let d2 = <GreeterComponentContext name="" greeting="" />
Upvotes: 1