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.

3
  • 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? Commented Apr 12, 2019 at 20:27
  • Tell us how you intend to use this base class. Commented Apr 12, 2019 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. Commented Apr 12, 2019 at 20:30

2 Answers 2

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
        })
      );
  };
Sign up to request clarification or add additional context in comments.

3 Comments

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
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. reactjs.org/docs/composition-vs-inheritance.html
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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.