How to use HOC with redux compose and Typescript

2019-07-16 14:52发布

问题:

I have two HOC, which want to use with redux compose, but the compiler doesn't make correct type. Compose declares function is from redux source code. If we paste the code in the playground. We will see different types of first and second variables.

type Func1<T1, R> = (a1: T1) => R

type Component<Props> = (props: Props) => string;

declare function compose<T1, A, R>(
  f1: (b: A) => R,
  f2: Func1<T1, A>
): Func1<T1, R>

declare const HOC1: <Props>(component: Component<Props>)
    => Component<Props & { prop: string }>

declare const HOC2: <Props>(component: Component<Props>)
    => Component<Props & { prop: number }>

declare const component: Component<{props: boolean}>

const first = HOC1(HOC2(component));

const second = compose(HOC1, HOC2)(component);

回答1:

We can't model a good version of compose in the current typescript type system. There is no way to capture generic type parameters to the HOCs.

We can create a version that might work in some circumstances based on the way the type parameters get erased (basically they are just replaced with the narrowest type in this case {}). This means we can get the props that are added by the HOC. I don't know how well this will work, but it does work for your sample:

type Func1<T1, R> = (a1: T1) => R

type Component<Props> = (props: Props) => string;

declare function compose<A, R, R2>(f1: (b: A) => Component<R>,f2: (b: A) => Component<R2>,): (<P>(c: Component<P>) => Component<P & R & R2>)

declare const HOC1: <Props>(component: Component<Props>)
    => Component<Props & { prop1: string }>

declare const HOC2: <Props>(component: Component<Props>)
    => Component<Props & { prop2: number }>

declare const component: Component<{props3: boolean}>

const a = HOC1(HOC2(component));

const b = compose(HOC1, HOC2)(component); //Component<{ props3: boolean; } & { prop1: string; } & { prop2: number; }>

Playground link