2
votes

I'm trouble with creating store with redux and typescript. This is actions.js:

import { Action } from 'redux';

export interface ITodoAction extends Action {
    todo:string;
}

export const ADD_TODO:string = 'ADD_TODO';
export function addTodo(todo:string):ITodoAction {
    return {
        type: ADD_TODO,
        todo
    };
}

I exported interface for custom action named ITodoAction, extended Action for my custom property todo:string.

This is reducers.js:

import { Reducer } from 'redux';
import { ITodo } from '../interfaces';
import { ITodoAction, ADD_TODO } from '../actions';

let id:number = 0;
const generateId = ():number => id++;

interface ITodoState {
    todos:Array<ITodo>
};

const defaultState:ITodoState = {
    todos: []
};

export function todoReducer(state:ITodoState = defaultState, action:ITodoAction):ITodoState {
    switch(action.type) {
        case ADD_TODO:
            return Object.assign({}, state, {
                todos: [
                    { id: generateId(), text: action.todo, completed: false },
                    ...state.todos
                ]
            });
        default:
            return state;
    }
}

I used ITodoAction from previous actions.js fir defining todoReducer. todoReducer will returns ITodoState instance, which looks like:

{
   type: 'ADD_TODO',
   todos: [ ITodo{}, ITodo{}, ITodo{}, ... ]
}

And this is ITodo interface that I was used:

export interface ITodo {
    id:number;
    todo:string;
    completed:boolean;
}

It just plain object that contains id, text, completed. I think it seems fine, but when I tried to create store with reducer like this:

import { createStore } from 'redux';
import todoReducer from './reducers';

export const store = createStore(todoReducer);

it fails with:

Argument of type 'typeof "/.../typescript-todo/src/ts/reducers/index"' is not assignable to parameter of type 'Reducer<{}>'...
Type 'typeof "/./typescript-todo/src/ts/reducers/index"' provides no match for the signature '&lt;A extends Action&gt;(state: {}, action: A): {}'

Looks like I have to fix my reducer, but I didn't get it how to define reducer with Reducer<{}>, every I attempts were failed with similar message, like "blablabla is not assignable to blablabla".

What I want is just using my simple reducer, but why I can't? It won't worked with combineReducer either, at this time, it needed to use some kind of ReducerMap or something, I don't remember what actual interface was.

I found lots of typescript + redux related posts, but they didn't used Reducer<{}> or Action>T< like something, they just used they're own defined Action and Reducer, but those are just made me confuse, why they didn't used Reducer and Action interface, and why It worked?

Somehow, I found the type declaration of redux, and this is how Reducer<{}> looks like:

export type Reducer<S> = <A extends Action>(state: S, action: A) => S;

As possible as I can understand is Reducer<{}> is a function that returns state. Then why my todoReducer not worked with them? I tried with Reducer<ITodoState>, but it won't worked.

I'm really confusing now, and looks like I'm missing something big, but, wow, I really don't get it what am I missing. I never thought that using Redux with TypeScript could be hard.

I tried my best, but looks like I need a hand. Any advice will very appreciate.

1
I'm running into the same issue. Have you found any resolution? - erik-sn
@erik-sn Actually yes, just change export function todoReducer to export default function todoReducer and it worked. - modernator

1 Answers

0
votes

Fixed, just export reducer as default, and it worked.