Husam Younis is a senior software engineer at BlazeMeter, with 5 years of experience in full-stack web development. He has extensive experience in web development technologies, cross-platform and responsive web applications, and a thorough background in software engineering methodologies and applications.

Learn JMeter in 5 Hours

Start Learning
Slack

Run massively scalable performance tests on web, mobile, and APIs

Sep 05 2018

JavaScript to TypeScript Migration: 5 Best Practices

As a GUI-focused BlazeMeter developer, it is very important for me to be able to understand and test all of our code, including our Legacy Code. That’s why I came up with the initiative to migrate our code from JavaScript to TypeScript. Changing our code to TypeScript helped us manage our code better, reduced our bugs and enabled faster deployment.

 

Based on our lessons learned, here are 5 best practices when migrating your code from TypeScript to JavaScript:

 

1. Set code improvement goals

 

TypeScript, JavaScript and other languages or frameworks each have different advantages and are fit for different kinds of projects. Once you understand that your current language doesn’t fit your needs, map out what those needs are, so you can be sure that the new language will answer them. It would be a shame to go through a whole migration project only to find yourself at square one.

 

We had two top goals. One, ensuring the GUI code functions are clear to anyone - experienced programmers who have been here from day one, as well as novices who just joined the team. Two, making the migration easy and the learning curve shorter for js users.

 

TypeScript’s advantages are many, with the main ones being its strict typing guidelines, the fact that it’s build on JavaScript, its maturity, the wide support available and the faster compilation it provides. These advantages answered our goals, so migrating from JS to TS was a good fit for us. You can learn more about JS vs. TS from here.

 

2. Get the whole development team on board

 

As a team, we deliberated between two options: TypeScript (by Microsoft) and Flow (by Facebook). To decide between them, we demoed each one (I demoed TypeScript, another team member deomed Flow). We researched the differences between then, the team asked questions and at the end we voted. For TypeScript, obviously. This choosing method ensured the whole team was a part of the decision, that all concerns were addressed and that the decision wasn’t being seen as taken lightly. This helped with adapting TS and making it an integral part of our code development.

 

3. Migrate your js files gradually to ts/tsx

 

Rome wasn’t built in a day, and neither can a TypeScript migration be. Changing your code from JavaScript to TypeScript requires changing files with the .js extension to .ts or.tsx, adding signatures, building types and interfaces, and making sure nothing breaks in the process. Instead of changing it all at once, we decided to switch gradually. The method we chose was that during each sprint, each developer would migrate a few files from js to ts/tsx, as part of their sprint tasks. This way, we ensured that our work wasn’t disrupted, developers didn’t feel threatened from the sudden change and our product didn’t suddenly break.

 

4. Create a temporary compiler for both js and ts/tsx

 

Because the migration was gradual, our system had to be able to deal with a middle stage where the code is made up of both JavaScript and of TypeScript. This caused problems in our compilation and our unit tests. Fixing that was up to me and I decided to create a temporary compiler for both js and ts/tsx. So here’s how I did it:

 

Webpack Configuration

 

Configuring webpack was easy, all I had to do was add awesome-typescript-loader to my loaders list:

 

{ test: /\.tsx?$/, loader: 'awesome-typescript-loader', exclude: /node_modules/ },

 

and add:

 

{enforce: 'pre',

 

to babel-loader.

 

Unit Testing

 

Mocha uses ts-node to compile typescript files, while webpack uses awesome-typescript-loader. Both act a bit differently since ts-node doesn’t support language features that are not a part of the ECMAScript standard. One of these was module imports. So, one of the most common errors I kept getting in tests was:
 TypeError: Cannot read property 'createElement' of undefined, even though at the top of the file I had:

 

import React from react;

 

After a lot of tinkering I found that changing the imports to the following style solved the problem:


 

import * as React from react;

 

It’s not pretty but it worked. However, changing the default imports in all the files was a lot of boring work and didn’t feel right. So back to Google. After a lot of research, turns out the solution was a simple flag change in the tsconfig.json file and changing the esModuleInterop property to “true”. Boom, all good.

 

Code Coverage

 

Babel coverage requires you to have:

 

"instrument": false,
"sourceMap": false 

 

While ts-node requires you to have both of them set to true. This was a bit tricky to get right, while the rest was basically the same. My solution was to simply separate the ts and the js coverage into different npm scripts, run them in parallel in another npm script, merge the output into one single coverage file and the report the output.

 

So it looks like this:

 

"tscoverage": "nyc --nycrc-path=.nycrc-ts mocha -R min ‘./app/**/*-spec.{ts,tsx}'"
 
"jscoverage": "BABEL_ENV=coverage nyc --nycrc-path=.nycrc-js mocha -R min ‘./app/**/*-spec.js’"
 
"coverage-report": "nyc report --include \"./coverage/{js,ts}-coverage/coverage-final.json\" --reporter=text-summary --reporter=cobertura --reporter=html --reporter=json-summary --reporter=lcov",
 
"coverage": "concurrently \"npm run tscoverage\" \"npm run jscoverage\" && npm run coverage-report

 

Production

 

Building to production worked out of the box! Phew!

 

5. Read A LOT about TypeScript

 

Read, read and again, read, as much as you can about the TypeScript syntax and compiler. Migrating is a complicated project that can have many unexpected fallouts. The more you read the more you will be able to plan and avoid errors, and also react quicker and smarter to surprising outcomes.

 

Two recommended reads:

 

I read a lot and am still reading, and that’s part of what made our migration successful.

 

The TypeScript migration helped me understand our code much better, which in turn helps me develop smarter and more efficient code with less bugs. But a deeper code understanding has even more advantages. Wider knowledge of your code coverage enables writing better performance tests, gaining more insights from test results and fixing bugs faster.

 

One more final tip: always run performance tests after commiting code. BlazeMeter enables you to run performance tests as part of your continuous testing process, as well as high-scale load tests before big releases. Request a demo to learn more, or try us out yourself by putting your URL in the box below.

You might also find these useful:

Interested in writing for our Blog?Send us a pitch!

Your email is required to complete the test. If you proceed, your test will be aborted.