6

I'm using redux-promise-middleware with redux-thunk in order to chain my promises:

import { Dispatch } from 'redux';

class Actions {
    private static _dispatcher: Dispatch<any>;
    public static get dispatcher(): Dispatch<any> {
        return Actions._dispatcher;
    }
    public static test() {
        this.dispatcher({
            type: 'MY_ACTION',
            payload: new Promise(resolve => resolve('hi'));
        }).then(result => {
            console.log(result); // this works
        });
    }
}

The code above works but also generates a warning during compile time:

TS2339: Property 'then' does not exist on type '{ type: string; payload: Promise<{}>; }'

It sounds like I need to include Promise<...> somewhere as a type so typescript knows that then is in fact a property on the object that's returned by dispatcher() but I haven't been able to remove the error.

https://github.com/gaearon/redux-thunk/issues/103

import { Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { getStore, IState } from './my_store';

let store = getStore();

// Create myThunkAction function with a type of ThunkAction<R, S, E>
let myThunkAction: ThunkAction<Promise<string>, IState, null> =
    (dispatch: Dispatch<IState>, getState: () => IState) => {
        return new Promise<string>((resolve, reject) => {

            // do async stuff with getState() and dispatch(), then...
            resolve('done!');

        });
    }

store.dispatch(myThunkAction)
.then(() => {
    // do stuff after the thunk has finished...
});

Seems related but where I can specify the action type i.e. MY_ACTION?

FuzzyTree
  • 32,014
  • 3
  • 54
  • 85

1 Answers1

4

As you can see in this ts playground the variable a exposes the same keys as the type ofDispatch<any>, and as you can see if you mouse over the error, the error message is the same as in your case. In order to access the promise (and there for the then function) you will have to access the payload of the Dispatch object.

this.dispatcher({ ... }).payload.then(....);

Edit1:

If we take a look at the typings for redux we can quite quickly find the Dispatcher interface.

export interface Dispatch<S> {
    <A extends Action>(action: A): A;
}
export interface Action {
  type: any;
} 

And then through some rewriting and some liberal use of psudocode, we can deduct that the type of Dispatch is a function that takes one argument witch is an object and returns an object of the same type as the argument.

type Dispatch: (action: {type: any, ...}) => {type: any, ...}

Both the input object and the output object is of the type:

interface {
    type: any,
    [key: string]: value
}

In conclusion, either 1) you are not using the official typings for redux, 2) the official typings for redux is wrong, or 3) you have missed something in your live environment were in fact the code doesn't work.

Edit2:

I haven't tried this code, so i have no idea if it will actually solve your problem. But you could try to redefine the Dispatch interface.

declare module 'redux' {
    export interface Action {
       type: any;
    }
    export interface Dispatch<S> {
        <A extends Action>(action: A): Promise<S>;
    }
}

It is valid typescript as you can see in this playground, but I haven't had to do this my self before, so this might not work out of the box.

If that doesn't work you could try defining a namespace with the same name as the module.

namespace redux {
    export interface Action {
       type: any;
    }
    export interface Dispatch<S> {
        <A extends Action>(action: A): Promise<S>;
    }
}

Still I haven't tried this before, so I cant guarantee it will work.

Olian04
  • 6,480
  • 2
  • 27
  • 54
  • Using `.payload.then` instead of `.then` breaks the code i.e. `Cannot read property 'then' of undefined`. To be clear the code I posted works but shows an error I want to eliminate – FuzzyTree Nov 01 '17 at 21:06
  • @FuzzyTree Then I'm afraid you will have to be more specific about where your error occurs. Because the error message you have provided says that the error occurs when trying to access a method named `then` on an object of type `{ type: string; payload: Promise<{}>; }`. And since the code you provided only has one occurrence of the term `then`, one would be lead to believe that that were the place in the code that the error originated from. – Olian04 Nov 01 '17 at 21:10
  • The error is definitely triggered by the provided code but it only occurs during compile time when typescript does its type checking. Everything works correctly during runtime and I am able to see the result of the promise. My guess is my `dispatcher` type is incorrect so typescript doesn't know that it returns a promise and that `then` is available – FuzzyTree Nov 01 '17 at 21:12
  • @FuzzyTree Could you provide your `dispatcher` type? – Olian04 Nov 01 '17 at 21:14
  • It's `redux.Dispatch`. Sorry am new to typescript so let me know if I can provide more info – FuzzyTree Nov 01 '17 at 21:15
  • 1
    @FuzzyTree Please have a look at my latest edit. Also, don't worry about being new. Typescript is very powerful but it takes time to understand fully. – Olian04 Nov 01 '17 at 21:27
  • I believe that redux-thunk middleware changes what is returned by `Dispatch` – FuzzyTree Nov 01 '17 at 21:36
  • @FuzzyTree In that case you would have to get the typings for `redux-thunk`, however that is out of scope for this question thread i believe :) Feel free to accept my answer (press the check mark) if you think its been helpful. – Olian04 Nov 01 '17 at 21:48
  • I mentioned redux-thunk from the beginning so it is in scope ;). However you have been helpful which is why I upvoted your answer. – FuzzyTree Nov 01 '17 at 21:50