Redux: Error in types for middleware (typescript 2.4.1)

Created on 29 Jun 2017  路  19Comments  路  Source: reduxjs/redux

It is a bug

I have this simple middleware:

import { Middleware, Store, Dispatch, Action } from 'redux';
import { AppState } from 'types/appState';

export default function createSimpleMiddleware(): Middleware {
  return (store: Store<AppState>) => (next: Dispatch<AppState>) => (action: Action): Action => {
    return next(action);
  };
}

It is useless, but there is a problem) This code works with typescript version 2.3.x and below. But in typescript 2.4 there is an Error.

What is the current behavior?
In typescript I have this Error:

Types of parameters 'store' and 'api' are incompatible.
    Type 'MiddlewareAPI<S>' is not assignable to type 'Store<AppState>'.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar.

You can find demo code at the top of current issue.

What is the expected behavior?

I expect, that there won't be any errors.

Which versions of Redux, and which browser and OS are affected by this issue? Did this work in previous versions of Redux?

Typescript: 2.4.1
Redux: 3.7.1
NodeJS: 6.9.1
OS: MacOS

Most helpful comment

This is my workaround for now:

declare module 'redux' {
  export interface Middleware<T=any> {
    <S>(api: MiddlewareAPI<S>): (next: Dispatch<S>) => Dispatch<S>;
    (api: MiddlewareAPI<T>): (next: Dispatch<T>) => Dispatch<T>;
  }
}

@timdorr Shouldn't we reopen this until it is fixed?

All 19 comments

Just merged this in yesterday: #2467

@timdorr but my bug is not about reducers. It is about middleware) Fix from #2467 fixes many problems, yes, but not for middleware.

Sorry, this is all sort of a mess and I'm not well-versed in TS. Is #2483 related?

@artem-malko could you test this pr #2479 with [email protected], it works well in my project.

@timdorr I understand. No #2483 is about reducers too, not about middleware)
@morlay no, my example is not working(

Types of parameters 'store' and 'api' are incompatible.
    Type 'MiddlewareAPI<S>' is not assignable to type 'Store<AppState>'.

And if I change code to:

import { Middleware, MiddlewareAPI, Dispatch, Action } from 'redux';
import { AppState } from 'types/appState';

export default function createSimpleMiddleware(): Middleware {
  return (store: MiddlewareAPI<AppState>) => (next: Dispatch<AppState>) => (action: Action): Action => {
    return next(action);
  };
}

It has errors too:

ypes of parameters 'store' and 'api' are incompatible.
    Type 'MiddlewareAPI<S>' is not assignable to type 'MiddlewareAPI<AppState>'.
      Type 'S' is not assignable to type 'AppState'.

@timdorr @morlay hey, any updates?)

@artem-malko after [email protected] change the generics check,

Middleware should change the position ofS too.

export interface Middleware<S> {
  (api: MiddlewareAPI<S>): (next: Dispatch<S>) => Dispatch<S>;
}

Middleware should change the position of S too.

Most middlewares can work regardless of state type, so in these cases, it's not a type parameter of Middleware, but of its call signature.

As you can see in typings for Store enhancers, there are two versions: one for fixed state type, and one generic. I think we should follow the same approach for middleware.

@morlay @aikoven yes, I have just copied all types for redux and made as @morlay said. And it works.

I have the same problem and don't really know how to overcome this without forcing an <any> and then cast back to <State>. That's a dirty cheat and I don't like it.

My function is as small as this: http://i.imgur.com/qcxGmoj.gifv

What should I do to fix this? I don't understand half of the messages above, sorry :-/

My typescript version is 2.5.0-dev.20170712. The same happens with 2.4.1

I have reducers correctly typed, as you can see createStore returns my State type.

@Llorx What error do you get?

@aikoven Ok, this is weird. I had a method that accepted a State parameter and when I do store.getState() it break saying that S cannot be converted to State, so, meanwhile, I foced an any.

Now I removed the any cast to see the error again and it works...: http://i.imgur.com/8ikVGgM.gifv

I guess that I had a type problem elsewhere that affected here. I thought that the IDE should show MiddlewareAPI<State> instead of MiddlewareAPI<S> to tell that detected the type correctly, that's why I showed the first gif, but seems that it doesn't.

I can reproduce the error:

Types of parameters 'store' and 'api' are incompatible.
    Type 'MiddlewareAPI<S>' is not assignable to type 'MiddlewareAPI<IState>'.
      Type 'S' is not assignable to type 'IState'.

I tried to change the typings for Middleware as @morlay suggested, but it clashed with reduxThunk.

TypeScript: 2.4.2
Redux: 3.7.2
NodeJS: 8.1.4
OS: MacOS

This is my workaround for now:

declare module 'redux' {
  export interface Middleware<T=any> {
    <S>(api: MiddlewareAPI<S>): (next: Dispatch<S>) => Dispatch<S>;
    (api: MiddlewareAPI<T>): (next: Dispatch<T>) => Dispatch<T>;
  }
}

@timdorr Shouldn't we reopen this until it is fixed?

Please reopen, this is not fixed yet. I still have the same error too

TypeScript: 2.4.2
Redux: 3.7.2
NodeJS: 7.7.3
OS: MacOS

Can someone work up a fix PR?

Should be fixed by #2563

Is it possible to add an example of what a valid middleware would look like with typescript? Even after following this thread, I'm unsure how to update my middleware so that it compiles correctly and types are satisfied.

@macdonaldr93 See the tests for Middleware types.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ilearnio picture ilearnio  路  3Comments

cloudfroster picture cloudfroster  路  3Comments

benoneal picture benoneal  路  3Comments

ms88privat picture ms88privat  路  3Comments

rui-ktei picture rui-ktei  路  3Comments