Skip to content

Instantly share code, notes, and snippets.

@pyldin601
Last active January 30, 2019 09:28
Show Gist options
  • Save pyldin601/ce6af1217628cb31402f82d1e948becf to your computer and use it in GitHub Desktop.
Save pyldin601/ce6af1217628cb31402f82d1e948becf to your computer and use it in GitHub Desktop.
Examples of strongly-typed HOCs written on Typescript
export type IComponentEnhancer<I, O> = (
Component: React.ComponentType<I>,
) => React.ComponentType<O>;
export function compose<A>(): IComponentEnhancer<A, A>;
export function compose<A, B>(hoc1: IComponentEnhancer<A, B>): IComponentEnhancer<A, B>;
export function compose<A, B, C>(
hoc1: IComponentEnhancer<B, C>,
hoc2: IComponentEnhancer<A, B>,
): IComponentEnhancer<A, C>;
export function compose<A, B, C, D>(
hoc1: IComponentEnhancer<C, D>,
hoc2: IComponentEnhancer<B, C>,
hoc3: IComponentEnhancer<A, B>,
): IComponentEnhancer<A, D>;
export function compose<A, B, C, D, E>(
hoc1: IComponentEnhancer<D, E>,
hoc2: IComponentEnhancer<C, D>,
hoc3: IComponentEnhancer<B, C>,
hoc4: IComponentEnhancer<A, B>,
): IComponentEnhancer<A, E>;
export function compose<A, B, C, D, E, F>(
hoc1: IComponentEnhancer<E, F>,
hoc2: IComponentEnhancer<D, E>,
hoc3: IComponentEnhancer<C, D>,
hoc4: IComponentEnhancer<B, C>,
hoc5: IComponentEnhancer<A, B>,
): IComponentEnhancer<A, F>;
export function compose<A, B, C, D, E, F, G>(
hoc1: IComponentEnhancer<F, G>,
hoc2: IComponentEnhancer<E, F>,
hoc3: IComponentEnhancer<D, E>,
hoc4: IComponentEnhancer<B, C>,
hoc5: IComponentEnhancer<C, D>,
hoc6: IComponentEnhancer<A, B>,
): IComponentEnhancer<A, G>;
export function compose<A, B, C, D, E, F, G, H>(
hoc1: IComponentEnhancer<G, H>,
hoc2: IComponentEnhancer<F, G>,
hoc3: IComponentEnhancer<E, F>,
hoc4: IComponentEnhancer<D, E>,
hoc5: IComponentEnhancer<C, D>,
hoc6: IComponentEnhancer<B, C>,
hoc7: IComponentEnhancer<A, B>,
): IComponentEnhancer<A, H>;
export function compose<A, B, C, D, E, F, G, H, I>(
hoc1: IComponentEnhancer<G, H>,
hoc2: IComponentEnhancer<F, G>,
hoc3: IComponentEnhancer<E, F>,
hoc4: IComponentEnhancer<D, E>,
hoc5: IComponentEnhancer<C, D>,
hoc6: IComponentEnhancer<B, C>,
hoc7: IComponentEnhancer<A, B>,
...otherHocs: IComponentEnhancer<any, any>[]
): IComponentEnhancer<A, I>;
export function compose(...hocs: IComponentEnhancer<any, any>[]): IComponentEnhancer<any, any> {
return hocs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
}
import * as React from 'react';
import { Subtract } from 'utility-types';
// Stateless component
export interface FooProps {
foo: string;
bar: number;
}
export const Foo: React.StatelessComponent<FooProps> = () => null;
const foo = <Foo foo="123" bar={33} />;
// High-order component, that injects props into component
export interface IInjectedBarProps {
bar: number;
}
const withInjectedBar = <T extends FooProps>(Component: React.ComponentType<T>) => {
type IOuter = Subtract<T, IInjectedBarProps>;
const OuterComponent: React.StatelessComponent<IOuter> = props => (
<Component {...props as T} bar={47} />
);
return OuterComponent;
};
const FooWithBar = withInjectedBar(Foo);
const fooWithBar = <FooWithBar foo="123" />;
// High-order component, that consumes props from component
export interface IConsumedBazProps {
baz: boolean;
}
const withConsumedBaz = <T extends {}>(Component: React.ComponentType<T>) => {
type IOuter = T & IConsumedBazProps;
const OuterComponent: React.StatelessComponent<IOuter> = props => {
const { baz, ...otherProps } = props;
return <Component {...otherProps as T} />;
};
return OuterComponent;
};
const FooWithBaz = withConsumedBaz(Foo);
const fooWithBaz = <FooWithBaz foo="123" bar={33} baz={false} />;
// Compose of high-order components
const ComposedFoo = withConsumedBaz(withInjectedBar(Foo));
const composedFoo = <ComposedFoo foo="123" baz={true} />;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment