How to Use Typescript with React and Redux

A guide to developing React and Redux apps with Typescript

Ross Bulat
Feb 13, 2019 · 10 min read
Image for post
Image for post

Supercharge the stability of your React apps, with Typescript

Installing Create React App with Typescript

yarn create-react-app app_name --typescript#ornpx create-react-app app_name --typescript

Installing TSLint-React

yarn global add tslint typescript tslint-react
tslint --init
{
"defaultSeverity": "error",
"extends": [
"tslint-react"
],
"jsRules": {
},
"rules": {
"member-access": false,
"ordered-imports": false,
"quotemark": false,
"no-console": false,
"semicolon": false,
"jsx-no-lambda": false
},
"rulesDirectory": [
],
"linterOptions": {
"exclude": [
"config/**/*.js",
"node_modules/**/*.ts"
]
}
}

Sublime Text 3 Packages

yarn add tslint tslint-react

VS Code Extension

Interfaces and Types for Props and State

Defining interfaces

interface FormProps {
first_name: string;
last_name: string;
age: number;
agreetoterms?: boolean;
}
interface FormState {
submitted?: boolean;
full_name: string;
age: number;
}

Applying interfaces to components

export class MyForm extends React.Component<FormProps, FormState> {
...
}
function MyForm(props: FormProps) {
...
}

Importing interfaces

// src/types/index.tsxexport interface FormProps {
first_name: string;
last_name: string;
age: number;
agreetoterms?: boolean;
}
// src/components/MyForm.tsximport React from 'react';
import { StoreState } from '../types/index';
...

Working with enums

// define enum
enum HeardFrom {
SEARCH_ENGINE = "Search Engine",
FRIEND = "Friend",
OTHER = "Other"
}
//construct heardFrom array
let heardFrom = [HeardFrom.SEARCH_ENGINE,
HeardFrom.FRIEND,
HeardFrom.OTHER];

//get submitted form value

const submitted_heardFrom = form.values.heardFrom;

//check if value is valid

heardFrom.includes(submitted_heardFrom)
? valid = true
: valid = false;

Working with iterables

for (let i in heardFrom) {
console.log(i); // "0", "1", "2",
}
for (let i of heardFrom) {
console.log(i); // "Search Engine", "Friend", "Other"
}

Typing Events

Image for post
Image for post
Hovering over handleChange() to obtain the event type
const {name, value}: {name: string; value: string;} = e.target;
const {name, value}: any = e.target;

Redux with Typescript

Step 1: Typing the Store

// src/types/index.tsxexport interface MyStore {
language: string;
country: string;
auth: {
authenticated: boolean;
username?: string;
};
}

Step 2: Defining action types and actions

// src/constants/index.tsxexport const SET_LANGUAGE = 'SET_LANGUAGE';
export type SET_LANGUAGE = typeof SET_LANGUAGE;
export const SET_COUNTRY = 'SET_COUNTRY';
export type SET_COUNTRY = typeof SET_COUNTRY;
export const AUTHENTICATE = 'AUTHENTICATE';
export type AUTHENTICATE = typeof AUTHENTICATE;
// src/actions/index.tsximport * as constants from '../constants';
//define action interfaces
export interface SetLanguage {
type: constants.SET_LANGUAGE;
language: string;
}
export interface SetCountry {
type: constants.SET_COUNTRY;
country: string;
}
export interface Authenticate{
type: constants.AUTHENTICATE;
username: string;
pw: string;
}
//define actions
export function setLanguage(l: string): SetLanguage ({
type: constants.SET_LANGUAGE,
language: l
});
export function setCountry(c: string): SetCountry ({
type: constants.SET_COUNTRY,
country: c
});
export function authenticate(u: string, pw: string): Authenticate ({
type: constants.AUTHENTICATE,
username: u,
pw: pw
});

Step 3: Defining Reducers

// src/actions/index.tsxexport type Locality = SetLanguage | SetCountry;
// src/reducers/index.tsximport { Locality } from '../actions';
import { StoreState } from '../types/index';
import { SET_LANGUAGE, SET_COUNTRY, AUTHENTICATE} from '../constants/index';
export function locality(state: StoreState, action: Locality): StoreState {

switch (action.type) {
case SET_LANGUAGE:
return return { ...state, language: action.language};
case SET_COUNTRY:
return { ...state, country: action.country};
case AUTHENTICATE:
return {
...state,
auth: {
username: action.username,
authenticated: true
}
};
}
return state;
}

Step 4: Creating the initial Store

// src/index.tsximport { createStore } from 'redux';
import { locality } from './reducers/index';
import { StoreState } from './types/index';
const store = createStore<StoreState>(locality, {
language: 'British (English)',
country: 'United Kingdom',
auth: {
authenticated: false
}
});

Mapping State and Dispatch

// mapStateToProps exampleimport { StoreState } from '../types/index';interface LocalityProps = {
country: string;
language: string;
}
function mapStateToProps (state: StoreState, ownProps: LocalityProps) ({
language: state.language,
country: state.country,
});
// mapDispatchToProps exampleconst mapDispatchToProps = {
actions.setLanguage,
actions.setCountry
}
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

In Summary

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

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store