Skip to content

Incorrect typescript typings for middlewares #2740

Closed
@nenadalm

Description

@nenadalm

Hi. It looks like typings don't work nicely for middlewares because I can't use type of state in it, because it's type is S (see the comment in code):

import * as redux from 'redux';

interface State {
    app: {
        title: string;
    }
}

const initialState: State = {
    app: {
        title: 'awesome app',
    }
}

function createMiddleware(): redux.Middleware {
    return function<S>(api: redux.MiddlewareAPI<S>) {
        return function (next: redux.Dispatch<S>): redux.Dispatch<S> {
            return function (action) {
                const state = api.getState();
                // error is shown here because `app` does not exist on type `S`
                console.log('app title: ', state.app.title);

                next(action);
            };
        };
    }
}

function appReducer(state: State, action) {
    return state;
}

redux.createStore(
    appReducer,
    initialState,
    redux.applyMiddleware(createMiddleware())
)

My colleague advised me to extend redux.Middleware but then typings don't work either because following code should fail to compile, but it compiles just fine (see the comment in code):

import * as redux from 'redux';

interface State {
    app: {
        title: string;
    }
}

export interface Middleware extends redux.Middleware {
    (api: redux.MiddlewareAPI<State>): (next: redux.Dispatch<State>) => redux.Dispatch<State>;
}

function createMiddleware(): Middleware {
    return function(api: redux.MiddlewareAPI<State>) {
        return function (next: redux.Dispatch<State>): redux.Dispatch<State> {
            return function (action) {
                const state = api.getState();
                // `state` is of type `State2` which doesn't have `app` property, but typescript happily compiles this
                console.log('app title: ', state.app.title);

                next(action);
            };
        };
    }
}

interface State2 {
    wtf: string;
}

const initialState2: State2 = {
    wtf: 'ttf'
}

function appReducer(state: State2, action) {
    return state;
}

redux.createStore(
    appReducer,
    initialState2,
    redux.applyMiddleware(createMiddleware())
)

environment:

  • redux: 3.7.2
  • typescript: 2.6.2

so applyMiddleware should probably take generic parameter for state and pass it to the middlewares?

// current definition
export function applyMiddleware(...middlewares: Middleware[]): GenericStoreEnhancer;

// should be probably defined something like:
export function applyMiddleware<S>(...middlewares: Middleware<S>[]): GenericStoreEnhancer;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions