Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
TypeScript React HOC using `forwardRef`
import * as React from 'react';
import { Component, ComponentClass, createRef, forwardRef, Ref } from 'react';
const myHoc = <ComposedComponentProps extends {}>(
ComposedComponent: ComponentClass<ComposedComponentProps>,
) => {
type ComposedComponentInstance = InstanceType<typeof ComposedComponent>;
type WrapperComponentProps = ComposedComponentProps & {
wrapperComponentProp: number;
};
type WrapperComponentPropsWithForwardedRef = WrapperComponentProps & {
forwardedRef: Ref<ComposedComponentInstance>;
};
class WrapperComponent extends Component<
WrapperComponentPropsWithForwardedRef,
{}
> {
render() {
const {
forwardedRef,
wrapperComponentProp,
...composedComponentProps
} = this.props;
return (
<ComposedComponent
ref={forwardedRef}
// We need a cast because:
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/32355
// https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046
{...composedComponentProps as ComposedComponentProps}
/>
);
}
}
return forwardRef<ComposedComponentInstance, WrapperComponentProps>(
(props, ref) => <WrapperComponent forwardedRef={ref} {...props} />,
);
};
type MyComponentProps = { composedComponentProp: number };
class MyComponent extends Component<MyComponentProps> {}
const ref = createRef<MyComponent>();
const badRef = createRef<ComponentClass<{}>>();
const MyComponentAfterHoc = myHoc(MyComponent);
//
// Tests
//
// should succeed:
<MyComponentAfterHoc composedComponentProp={1} wrapperComponentProp={1} />;
<MyComponentAfterHoc
composedComponentProp={1}
wrapperComponentProp={1}
ref={e => {}}
/>;
<MyComponentAfterHoc
composedComponentProp={1}
wrapperComponentProp={1}
ref={ref}
/>;
// should error:
<MyComponentAfterHoc
composedComponentProp={1}
wrapperComponentProp={1}
ref={badRef}
/>;
<MyComponentAfterHoc composedComponentProp={'1'} wrapperComponentProp={1} />;
<MyComponentAfterHoc composedComponentProp={'1'} wrapperComponentProp={'1'} />;
<MyComponentAfterHoc />;
@OliverJAsh

This comment has been minimized.

Copy link
Owner Author

@OliverJAsh OliverJAsh commented May 30, 2019

Actually, this doesn't quite cut it: if you try to pass the result of one HOC into another HOC, you'll get an error:

const MyComponentAfterHoc2 = myHoc(MyComponentAfterHoc);

See DefinitelyTyped/DefinitelyTyped#35834 (comment). The answer isn't pretty…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.