When we are writing a React Application and using React Redux to manage the application state we use a plain JavaScript. So its implies some difficulties, like: (i) code complete not available, that is, we do not have a suggestion about de code, parameters, properties and etc; (ii) static type checking is not working, making it impossible fast error detection and so on.
Install of dependencies
Thus the first step is configuring a React Project whit TypeScript. Now, we need install the React Redux dependencies:
yarn add redux react-redux
and the react-redux type definitions
yarn add @types/react-redux -D
State Types
To have the benefits of static type checking we need creating the types that will be used for state and actions creators.
Types definitions
/* types.ts */
export interface Todo {
id: number;
description: string;
checked: boolean;
}
export interface TodoState {
data: Todo[];
}
export const CREATE_TODO_REQUEST = "@todo/CREATE_TODO_REQUEST";
interface CreateTodoRequest {
type: typeof CREATE_TODO_REQUEST;
payload: { todo: Todo };
}
export type TodoActionsTypes = CreateTodoRequest;
Now that we have a interface defining how must be the format of our action, we can create it.
/* actions.ts */
import { TodoActionsTypes, Todo, CREATE_TODO_REQUEST } from "./types";
export function createTodo(todo: Todo): TodoActionsTypes {
return {
type: CREATE_TODO_REQUEST,
payload: { todo }
};
}
In next step we will creating a Reducer to manage the state and export the combineReducers together with the RootState type.
/* reducer.ts */
import { TodoState, TodoActionsTypes, CREATE_TODO_REQUEST } from "./types";
const initialState: TodoState = {
data: []
};
export default function todoReducer(
state = initialState,
action: TodoActionsTypes
): TodoState {
switch (action.type) {
case CREATE_TODO_REQUEST:
return {
data: [...state.data, action.payload.todo]
};
default:
return state;
}
}
/* combineReducers.ts */
import { combineReducers } from "redux";
import todoReducer from "./todo_list/reducer";
const rootReducer = combineReducers({
todo: todoReducer
});
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;
Access the state and dispatch action in a view
To access the state we can use the useSelector hook passing to it the RootState type so that we can saw our state structure
import { useSelector } from "react-redux";
import { RootState } from "../../store/modules/combineReducers";
const data = useSelector((state: RootState) => state.todo.data);
and using the useDispatch hook to fire our action.
import { useDispatch } from "react-redux";
import { createTodo } from "../../store/modules/todo_list/actions";
const dispatch = useDispatch();
dispatch(
createTodo({
id: lastId(),
description,
checked: false
})
);
In this quick post, using some code snippets, we saw a way to improve our code using TypeScript to static typing verifying of state on React Redux.
Top comments (5)
Hi, I'm a Redux maintainer. I'd specifically encourage you to try using our new official Redux Toolkit package, which includes utilities to simplify several common Redux use cases, including store setup, defining reducers, immutable update logic, and even creating entire "slices" of state at once.
As part of that, the Redux Toolkit "Advanced Tutorial" docs page shows how to use RTK with TypeScript together with our new React-Redux hooks API.
Hi Mark, thanks a lot by the tip. I going to read about...
Hi,
I tried running your code in local. It doesnt work for me :(.
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
at validateString (internal/validators.js:120:11)
Hi Kshitij Bisht, thanks by comment.
I didn't be able to reproduce this error.
I did:
and worked fine.
Yup, same error here.