Search code examples
javascriptreactjstypescriptenzyme

Shallow HOC with Enzyme and TypeScript


I have a HOC to test, during shallow mount I should to call some class methods:

it('Should not call dispatch', () => {
        const dispatch = jest.fn()
        const WrappedComponent = someHoc(DummyComponent)
        const instance = shallow(
          <WrappedComponent
            dispatch={dispatch}
          />,
        ).instance() as WrappedComponent
        instance.someMethod()
        expect(dispatch).toHaveBeenCalledTimes(0)
})

test works fine but TS compiler throws an error

 Cannot find name 'WrappedComponent'.

And it is right because WrappedComponent is not a type or class, but if I remove the

 as WrappedComponent

line, TS throws an error

Property 'someMethod' does not exist on type 'Component<{}, {}, any>'.

Also, it does not compile if I change that line as

as typeof WrappedComponent

someHoc description:

import ...

interface State {
  /*state*/
}

interface Props {
  dispatch: Dispatch<Action>
  /*props*/
}

export someHoc = <T extends {}>(
  ChildComponent: React.ComponentClass<T>,
) => {
  class Wrapper extends React.PureComponent<T & Props, State> {

    someMethod = () => {
       /*do smth*/
    }

    render() {
      return (
        <div>
          <ChildComponent {...this.props} />
        </div>
      )
    }
  }

  return Wrapper
}

How can I type the HOC instance? Thanks.


Solution

  • It is expected that functions that have variable return value types that can be parametrized are generics. shallow is a generic:

    export function shallow<C extends Component, P = C['props'], S = C['state']>(node: ReactElement<P>, options?: ShallowRendererProps): ShallowWrapper<P, S, C>;
    export function shallow<P>(node: ReactElement<P>, options?: ShallowRendererProps): ShallowWrapper<P, any>;
    export function shallow<P, S>(node: ReactElement<P>, options?: ShallowRendererProps): ShallowWrapper<P, S>;
    

    It likely should be used as:

    const instance = shallow<typeof WrappedComponent>(
      <WrappedComponent
        dispatch={dispatch}
      />,
    ).instance();
    

    There currently seem to be problems in Enzyme typings with using generic parameters to infer component type in ShallowWrapper.

    A workaround that secures type safety down the test is to assert the type:

    const instance = shallow(
      <WrappedComponent
        dispatch={dispatch}
      />,
    )
    .instance() as any as InstanceType<typeof WrappedComponent>;