Typed React: A Robust Frontend Framework

Panagiotis Psimatikas
Slalom Build
Published in
8 min readFeb 16, 2018

The frontend development world has matured into using types —Why not use them in React?

The Problem

Over the past three years, I have worked on multiple React projects.
I have faced exciting challenges that forced me to solidify and perfect my patterns for using the React/Redux framework.

The diagram below describes how the framework all works together:

My React/Redux Pattern

But, there was always something missing…

The Incentive

During the discovery phase of a new project, the client challenged me to defend my choice of React over Angular 4. As an open minded architect, I always try to challenge my own decisions. So, I put a list of pros and cons together between React and Angular. I interviewed other Slalom Angular experts to see what they find so great about it... Every Angular fan out there will claim that Angular 4 is a more structured and robust framework. I was determined to find the root of its robustness. I observed Angular 4 developers in action and there was one common thing everybody seemed to be a fan of… Types!

Angular also favors dependency injection. I am a huge fan of using dependency injection for the backend. But I felt for front end it is:

  1. Overkill
  2. Adds extra overhead of setup and boilerplate
  3. Front end developers are not as accustomed to it

At this point, the only thing that my React framework was lacking was a way to use Types.

Why Types?

Types and OOP have existed since the “dawn of time” in programming languages. JavaScript strategically decided to drop types and go dynamic to attract non-developers in the creation of websites. In the ever evolving world of web, the demands on user interaction and performance have increased, and the need of developers and structured codebases is a necessity.

Below is an example of JavaScript code that fully compiles and is potentially deployable. This code has a huge bug that will break the application with a nasty runtime error.

import React from 'react';

require('./profile.scss');

export default class Profile extends React.Component {
public render() {
const { auht, logout } = this.props;

return (
<div className='profile-container'>
<span>Hi, {auht.user.username}</span>
<button type='button' onClick={logout}>Logout</button>
</div>
);
}
}

Did you find the error ? …

3

2

1

If you pay close attention the word “auth” is miss-spelled to “auht”.

I know we all have been there, debugging an issue to only realize that we have fat fingered a simple word.

Some of the benefits of using types are:

  1. Code Safety
    a. Compile-Time Errors
    b. Well-specified runtime errors
    c. Handles typos, wrong naming
    d. Benefits and Protects Junior engineers
  2. Robust Code with a structured strict framework enabling ease of development for new features.
  3. Increased Maintainability for large codebases
  4. Easy and Confident Refactoring

Choice of a Typed Language

I had to choose a typed language for my purpose. To be honest the choice was not that hard…

  1. TypeScript is a very well known and supported language by the community (most likely because of Angular 4 developers). An army of community devs support it (29,767+ github stars)
  2. TypeScript syntax is similar to JavaScript. It’s a superset of ES6.
  3. You can still use JavaScript libraries.
  4. As a Java expert, I love Decorators, so I love TypeScript. I do only use them for the backend code for now. But it enables the flexibility of using them for the front end framework.
  5. When I first start using TypeScript for backend purposes one year ago, there were not that many npm libraries that supported Types. Today there are over 3000 libraries that have been typed. Check this github repo out to find your library…

Some people might say, but why not Flow? Yes flow is indeed made by facebook and does play well with React. But:

  1. It will be hard to find your favorite npm libraries typed in Flow. They are not even close to as many libraries as TypeScript has type definitions for.
  2. TypeScript is accepted and known by the community, thanks to Angular. Additionally, we’re framework agnostic at Slalom, so we do a lot of projects using Angular and React. Using TypeScript for both makes it easier to go from an Angular project to a React project.
  3. The framework is full stack, supporting a backend server written purely in TypeScript. The server is inspired by Tim Whitney ‘s Typescript + Node.js Enterprise Patterns.
  4. TypeScript has decorators — Syntactic sugar which allow meta-information to be defined easily :)

The Implementation Journey

Now I had the language and my framework. It was time to start translating pieces of the framework into TypeScript. I started with the easy part, the services.

import { post, get } from './requestService';
import { User } from '../../server/domains/User';
import { Credentials } from '../../server/domains/Credentials';

export function login(credentials: Credentials): Promise<User> {
return post('/api/auth/login', credentials);
}

export function logout(): Promise<void> {
return post('/api/auth/logout', undefined);
}

export function getUser(): Promise<User> {
return get('/api/auth/user');
}

Then I wanted to see how easy would it be to change my React components into Typed components. Apparently that was also easy.

Untyped component:

import React from 'react';

require('./profile.scss');

export default class Profile extends React.Component {
public render() {
const { auth, logout } = this.props; // I have no idea what the auth or logout props are, at compile or coding time...

return (
<div className='profile-container'>
<span>Hi, {auth.user.username}</span>
<button type='button' onClick={logout}>Logout</button>
</div>
);
}
}

Type component:

import * as React from 'react';
import { AuthState } from '../../redux/models/AuthState';

require('./profile.scss');

export interface ProfileProps {
auth: AuthState;
logout: () => void;
}

export default class Profile extends React.Component<ProfileProps> {
public render() {
const { auth, logout } = this.props;

return (
<div className='profile-container'>
<span>Hi, {auth.user.username}</span>
<button type='button' onClick={logout}>Logout</button>
</div>
);
}
}

The power of having typed components was tenfold. The compiler will throw an error if you use the component without passing all the required parameters.

Compiler error:

😂

That was exciting, easy, and fun!

The main problem with using Redux in JavaScript is that you never know while coding what is in the Redux store. You usually have to run the app debug and see what’s in the store. This is a time consuming and error-prone process. Types to the rescue again!

I created classes for everything that is in my store.

The AppState class is the representation of my store:

import { AuthState } from './AuthState';

export interface AppState {
auth: AuthState;
}

Then, for each item in the store there is a different type:

import { User } from '../../../server/domains/User';

export interface AuthState {
error: boolean;
user: User;
}
export class User {
constructor(
public username: string
) {}
}

At that point anywhere in the code I know what my store looks like and what values are available to me.

I changed the rest of the framework pieces into fully typed classes and voila! React Redux framework as robust as Angular 4, without all the overhead, boilerplate, and unnecessary code to enable dependency injection!

The Ultimate Power

The most powerful functionality that a typed language adds into a framework is easy and quick refactoring. In the example below I wanted to refactor the name of a value inside my store; with the right IDE this is very simple, refactor / rename and done.

Refactoring with IntelliJ made easy

Extra robustness

I have had a streak of 5 projects that attained 100% test coverage. How could I ever break that streak? I added and configured Jest to implement unit tests and add coverage.

I also add TSLint for beautifully consistent code.

100% Unit Test Coverage!

My partner in crime on frontend development, Garret Jones, also suggested to add observables to the project with the use of RxJS. We decided to use the observables as a better way to connect the services with the Action Creators of redux.

Adding Observables to my Pattern

This gave us an extra level of isolation for how we fetch all the various data from different services and then push them into the store.

The Challenges

I did make the transition from JavaScript to TypeScript seem very simple in my journey above. But as every creation of a great framework it was challenging and with a lot of unexpected surprises.

I wanted to make this Typed React framework years ago, but TypeScript was not that popular or mature. Even now a lot of the typed libraries have changed the way they’re used from their original JavaScript versions. They come with no documentation and you usually have to dig deep inside the source code to figure out how it works.

Decorators are still experimental in TypeScript and I cannot wait for them to be production ready.

Webpacking this framework requires many transpilations from TypeScript to JavaScript and then down to the lowest version of JavaScript for the browser to understand. Surprisingly even after all those transpilations debugging in the browser is very possible through sourcemaps.

Debugging transpiled code in Chrome Dev Tools, but seeing the original source code!

My Takeaways

Transforming my framework into something better using the latest technologies made me rethink and revisit a lot of my past decisions, end eventually settle on some conclusions for using this framework in the future…

  1. Types are the (OLD) new thing
  2. I can now recommend my framework with confidence for projects of all sizes
  3. There is a slightly higher learning curve for frontend engineers without Angular 2+ experience
  4. It was a quick, easy, and fun way to learn TypeScript
  5. Even though TypeScript plays well with JavaScript (and it is easy and fast to write untyped code inside typed code), I would recommend avoiding the use of JavaScript at any cost

I really had fun creating this robust framework. I learned a lot along the way and I am super excited to start using it on my future projects!

If you are planning to familiarize yourself with my framework please check out the technologies below first:

  1. TypeScript
    a. Github
    b. DefinedTypes
  2. React
  3. React-Router 4
  4. Redux
    a. React-Redux
  5. RxJS
  6. Webpack 2
  7. Jest
Happy Typing!

--

--

Panagiotis Psimatikas
Slalom Build

Hello everybody, my name is Panos. I am a passionate software engineer that loves learning new technologies every day. I also want to own all the clouds !