Type Checking in React & Redux with TypeScript

Hayk Yaghubyan
Jan 29 · 4 min read

TypeScript is making stronger its positions in the JS community and many popular companies started using it with their react based front-end for type checking purposes. Let’s see how can we use TypeScript with React and Redux.

Adding TypeScript to existing create-react-app project

If you want to add TypeScript to the existing app, then install TypeScript and other required types

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

Then we need to rename the files to .ts or .tsx and then start the server. This will generate the tsconfig.json file automatically.

Using TypeScript with actions

export interface IStartFetchPostsAction extends Action<’StartFetchPosts’> {}export interface IFetchPostsSuccessAction extends Action<’FetchPostsSuccess’> {
posts: IPost[];
}
export type PostActions =
| IStartFetchPostsAction
| IFetchPostsSuccessAction

These action types extend the generic Action type that is coming with the Redux library. This ensures that we set the type property correctly when consuming the actions in our code.

As you see in the above we have PostsActions union type that references 2 above actions. We’ll later use this in the Posts reducer to be sure that we are working with the correct actions.

You may ask from where we are getting IPost[]. Well, there is a separate file where we created an interface for posts that look like this.

export interface IPost {
id: number;
title: string;
description: string;
...
}

As far as fetching posts from the back-end should be asynchronous action, here is where Redux-Thunk comes to solve our problem. However, Using TypeScript here will be a bit more challenging.

export const fetchPostsActionCreator: ActionCreator<
ThunkAction<
Promise<IFetchPostsSuccessAction>,
>
> = () => {
return async (dispatch: Dispatch) => {
const startFetchPostsAction: IStartFetchPostsAction = {
type: ‘StartFetchPosts’,
};
dispatch(startFetchPostsAction);
const posts = await fetch("API URL");
const fetchPostsSuccessAction: IFetchPostsSuccessAction = {
posts,
type: ‘FetchPostsSuccess’,
};
return dispatch(fetchPostsSuccessAction);
};
};

ActionCreator is a generic type from the Redux library that takes in the type to be returned from the action creator. The above action creator returns a function that will return IFetchPostsSuccessAction. ThunkAction might be strange for you for the first time. But it’s a generic that ships with Redux-Thunk library.

Using TypeScript with Reducers

Let’s see how will our Reducer look like when we implement TypeScript:

import { Reducer } from "redux";
import {
IPostsState,
PostsActions,
} from "./PostsTypes";
const initialPostState: IPostsState = {
posts: [],
isLoading: false
};
const postsReducer: Reducer<IPostsState, PostsActions> = (
state = initialPostsState,
action,
) => {
switch (action.type) {
case ‘StartFetchPosts’: {
return {
…state,
isloading: true,
};
}
case ‘FetchPostsSuccess’: {
return {
…state,
posts: action.posts,
isloading: false,
};
}
}
return state;
};

We also need a root reducer

import { combineReducers } from 'redux';
import PostsReducer from './reducers/PostsReducer'
const rootReducer = combineReducers<IAppState>({
Posts: postsReducer
});
export default rootReducer;

We use the generic Reducer type from the Redux library passing in our state type with the PostsActions union type.

The action argument within each case of switch statement has its type narrowed to the specific action that is relevant to the specific case.

Using TypeScript with Store

We are using the generic Store type from the Redux library passing in the type of our app state which is IAppState in this project. Let’s make changes inside our store.js

export function configureStore(): Store<IAppState> {
const store = createStore(rootReducer, undefined, applyMiddleware(thunk));
return store;
}

Using TypeScript inside Component

Let’s see how it will look like when we implement TypeScript inside our component.

import * as React from "react";
import { connect } from "react-redux";
import { RouteComponentProps } from "react-router-dom";
import { fetchPosts } from "./PostsActions";
import { IPost } from "./PostsData";
import PostsList from "./PostsList";
import { IAppState } from "./Store";
interface IProps extends RouteComponentProps {
loading: boolean;
posts: IPost[];
}
class PostsPage extends React.Component<IProps> {
public componentDidMount() {
this.props.fetchPosts();
}
public render() {
...
return (
<div className="page-container">

<PostsList
posts={this.props.posts}
loading={this.props.loading}
/>
</div>
);
}
}
const mapStateToProps = (store: IAppState) => {
return {
loading: store.posts.isLoading,
posts: store.posts.posts
};
};
const mapDispatchToProps = (dispatch: any) => {
return {
fetchPosts: () => dispatch(fetchPosts())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(PostsPage);

The mapStateToProps function uses our IAppState type so that the references to the stores' state is strongly-typed.

Wrapping Up

Integrating TypeScript inside the existing React project is not as scary as people think. Of course, it’s better to generate new project when you are starting development process of your startup and use TypeScript in the earliest stage but anyway in both cases now you are ready to accept that challenge :)

JavaScript in Plain English

Learn the web's most important programming language.

Hayk Yaghubyan

Written by

Senior full-stack developer working in ReactJS, Angular,Vue.js, Node.js, and other modern technologies. Excited about web technologies.

JavaScript in Plain English

Learn the web's most important programming language.

More From Medium

More from JavaScript in Plain English

More from JavaScript in Plain English

More from JavaScript in Plain English

5 Secret features of JSON.stringify()

More from JavaScript in Plain English

More from JavaScript in Plain English

7 really good reasons not to use TypeScript

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade