Migrating to Typescript; Stateless and Stateful Components

I am a Senior Front-End Engineer at Perkbox, working within a large team of FE developers split over 5 projects. Alongside the day-to-day feature building and bug fixing, we are encouraged to try new techniques and practices to increase the quality of our work and our overall working practices.

This article assumes you already have at least a basic understanding of React, and ES6 syntax.

About six months ago, we adopted Typescript within React Native as a new project was started, and then slowly, with lessons learned, those best practices were applied to our much larger library that had been written extensively in ES6.

One of the biggest obstacles found when starting was how to write or rewrite simple components. Just getting started with new approaches can be hard work with a steep learning curve, new syntax and terminology — hopefully, this article helps a little.

Starting with the basics, in these components, the differences are fairly minimal. In fact, if you already write your React using prop-types such as shape, and arrayOf this will be pretty straight forward for you anyway.

Here you can see that the render functions are identical — nothing really changes from a React point of view, the main difference is the communication around what is and is not allowed to be passed into this component.

An ES6 component on the left, with its Typescript counterpart on the right

As you can see here, the Props interface makes use of an interface called myObjectType — this, in practice, would be any sort of object you would use in your service or third party. Outside of the PropTypes/Interface, you can see that there are no other differences to the component, and so the migration is simple and quick.

To me, this summarises the difference between propTypes and Types — using a shape in this context, would tell the developer exactly what is used within the component — and if it is necessary or optional, the Type will show the developer everything that is potentially available as a child value of that object.

To that extent, it’s possible to theorise that if we were to import the propTypes shape from a shared file, it would have a similar effect on your code to the way Types are used.

Getting further into the migration, it became clear that the way developers manage State in ES6 has room for error, where the concept of “State Props” is missing when defining a component. This is where the benefits of Typescript begin to gain some traction.

In Es6, a developer can set state to whatever, pretty much whenever, leading to bugs, aswell as making it harder for the next developer to understand the component.

Again the majority of the component remains almost identical, there is one noticeable change to note. The State is defined as an interface — this means that your State properties -> values will always remain the same — a string will always be a string.

This allows us to manage our setState functions in a more explicit manner, subsequently helping to prevent the introduction of bugs.

In this example, there are a few things to note:

  • A defined “State interface”
  • the updateStateFunction has its input variable defined to match the State Interface — if this variable was changed to myNewString: boolean the linter would show an error
  • the render function doesn’t change

This means that as methods and logic gets shared and spread across multiple components, files, and folders, the risk of potential bugs is reduced, as tslint, can pick up these inconsistencies; i.e. if we pass a variable into a function introduced as a prop, that in turn sets the parent components state — if that variable is an object and not a string, the linter will error.

Whilst there is plenty more to the React & TypeScript way of working, Stateless and Stateful components are the bulk of most React work, and subsequently will provide the most value as the benefits of a Typed system are leveraged.

Upon migrating components; Stateless, Stateful, and more complex, a new understanding of where new bugs could have been introduced has also shone a light on where problems can be easily identified in the future. The biggest lesson taken away from this endeavour was as much about collaboration with other developers, as it was the logic used.

Front End Tech Lead, you can find me on github @thomasparsons