1

According to the typescript definition of Redux, those interfaces should be implemented to make a middelware:

/* middleware */

export interface MiddlewareAPI<D extends Dispatch = Dispatch, S = any> {
  dispatch: D
  getState(): S
}

/**
 * A middleware is a higher-order function that composes a dispatch function
 * to return a new dispatch function. It often turns async actions into
 * actions.
 *
 * Middleware is composable using function composition. It is useful for
 * logging actions, performing side effects like routing, or turning an
 * asynchronous API call into a series of synchronous actions.
 *
 * @template DispatchExt Extra Dispatch signature added by this middleware.
 * @template S The type of the state supported by this middleware.
 * @template D The type of Dispatch of the store where this middleware is
 *   installed.
 */
export interface Middleware<
  DispatchExt = {},
  S = any,
  D extends Dispatch = Dispatch
> {
  (api: MiddlewareAPI<D, S>): (
    next: Dispatch<AnyAction>
  ) => (action: any) => any
}

I tried this:

import { Middleware, Dispatch, AnyAction, MiddlewareAPI } from 'redux';
import { AppState } from 'AppState';

class MiddlewareBase implements Middleware<{}, AppState, Dispatch<AnyAction>> {
  constructor() {
    return (api: MiddlewareAPI<Dispatch<AnyAction>, AppState>) => 
        (next: Dispatch<AnyAction>) =>
           (action: AnyAction) =>
              {
                 // TODO: Do something before calling the next middleware.
                 return next(action);
              };
  }
}

export default MiddlewareBase;

But the compiler complains about this:

  Type 'MiddlewareBase' provides no match for the signature '(api: MiddlewareAPI<Dispatch<AnyAction>, AppState>): (next: Dispatch<AnyAction>) => (action: any) => any' 

Update:

It should be a class, not a function. I made a base class so I can inherit them later.

Nour
  • 5,252
  • 3
  • 41
  • 66
  • You'll get into trouble if you must use class. My advice, just don't. I don't see concrete reason you must. Some other mechanism instead of inheritance? – hackape Apr 12 '19 at 20:27
  • Tell us how you intend to use this base class. – hackape Apr 12 '19 at 20:27
  • If you return a function from constructor, instead of normally the `this` object, then there is no point to use a class. That function won't have access to the class prototype. – hackape Apr 12 '19 at 20:30

2 Answers2

5

You can look at my code. Should be something like this:

  import { MiddlewareAPI, Dispatch, Middleware, AnyAction } from "redux";

  const callAPIMiddleware: Middleware<Dispatch> = ({
    dispatch
  }: MiddlewareAPI) => next => (action: AnyAction | CallApiAction) => {
    if (!action.meta || !action.meta.callApi) {
      return next(action);
    }

    const { successAction, errorAction, url, params } = action.payload;

    return fetchFn(url, params)
      .then(res => res.json())
      .then(res =>
        dispatch({
          type: successAction,
          payload: res
        })
      )
      .catch(res =>
        dispatch({
          type: errorAction,
          payload: res
        })
      );
  };
nucleartux
  • 1,381
  • 1
  • 14
  • 36
  • Hey, thanks for the help, however, I need it to be a class, as it is inherited by other classes. I should've added that to the question I think – Nour Apr 12 '19 at 20:08
  • I think you can't do it. Because redux accepts functions as middlewares. You can of course make class with method that implements some logic but it will be function anyway. My advice: use composition of functions instead of inheritance. https://reactjs.org/docs/composition-vs-inheritance.html – nucleartux Apr 12 '19 at 20:29
  • If you add a second argument to `Middleware` with your application state's type and use `getState` (which is available alongside `dispatch`), then you don't want `MiddlewareAPI` here because that throws away `getState`'s return type. Just omit that `MiddlewareAPI`, and `getState` will return the second generic argument to `Middleware`. – Ahmed Fasih Jun 01 '22 at 04:22
0

There's no such thing as a "redux middleware class" in the first place. So the answer to your how-to question is simply, you can't.

Redux Middleware is a function interface, not a class interface. Although in javascript you could force return a function (instead of this object) from a class constructor, you shouldn't with typescript. The compiler will probably complain about it cus that's an antipattern, and the class syntax isn't meant for this hacky usage. Even if it doesn't complain, I see absolutely zero gain from such hack.

So you want to implement something that's "inheritable". You don't have to go with class syntax. You could use, ironically, middleware pattern. Apply base middleware before sub middleware give you inherit-ish effect.

Now I don't know what you intend to do, so not gonna makeup pointless examples. If you care to explain what you're trying to do, I'll look into it.

hackape
  • 18,643
  • 2
  • 29
  • 57