TypeScript for JavaScript Developers by Refactoring Part 1 of 2
Jeremy Likness ⚡️
Posted on March 5, 2019
Learn TypeScript by taking an existing JavaScript application and migrating it to TypeScript.
I created a repository with the goal of teaching TypeScript to JavaScript developers. Imagine if you could use a tool that finds defects for you automatically and makes it easier to squash bugs before they make it to production! This walk through demonstrates how.
The repository contains documentation paired with several commits to walk through the process. If you’re a hands-on person and want to dive in, visit the repository and get started right now! I recorded a companion video series to guide you through each step.
TypeScript
Each video is only a few minutes long so feel free to bookmark this page and come back often. You may have already found these videos from my Twitter thread.
Jeremy Likness ⚡️
@jeremylikness
I'm releasing a new video series with very short (2 - 5 min) clips to teach #TypeScript by refactoring existing #JavaScript. It'll have about 15 parts. I'll tweet each step here and finish with an article that pulls the clips together. Here is the repo: github.com/JeremyLikness/…
00:24 AM - 15 Feb 2019
1945
1. Introduction
In this step I introduce a simple JavaScript app that doesn’t behave properly when run with Node.js. I begin the migration to TypeScript by adding the TypeScript compiler, initializing its configuration, and renaming the index.js file to index.ts.
Note: an alternative way to initialize TypeScript’s configuration file is to use the npx command, like this: npx tsc --init
2. Configuration and the Spread (Rest) Operator
The TypeScript configuration is updated to turn off the requirement for strict typing. This removes all errors but one. The error happens to be a bug that was discovered by TypeScript. To fix the defect, a “spread operator” is used to allow a list of parameters to be passed in and parsed as an array. Because the older version of JavaScript doesn’t support the spread operator, TypeScript automatically generates the compatible code. This fix improves the application, but a few defects remain.
A major benefit of using TypeScript, as you may be able to guess from the name, is the ability to use classes and types. I refactor the code to use classes instead of function constructors and annotate the properties with types. This immediately uncovers another bug for us that will be easy to fix in the next step.
The class refactoring revealed a property that wasn’t named consistently. This is fixed by updating the constructor function to match the names use in other code. Next, a custom type is defined that declares the two possible string values for contactType: mobile and home. This reveals a defect that, when fixed, corrects the phone display logic.
A bug has surfaced due to the way variables are captured in scope in JavaScript. Rather than wrap the call with additional code that adds complexity, a simple change is to specify the variable with let. The TypeScript compiler then knows to manage scope for older versions of JavaScript and passes through to modern implementations.
Anyone familiar with JavaScript has encountered the issue of understanding exactly what this is. By default, scope is at a function level, so this.x has a different meaning in a nested function. Lambda expressions not only simplify the definition of functions, but also capture outer scope for a consistent hierarchy of variable access.
In TypeScript, as with modern JavaScript, you can use string templates for interpolation. This gives you a cleaner way to embed variables and evaluate expressions for output. TypeScript will turn it into string concatenation for older JavaScript versions and leverage the new syntax for modern targets.
Generics, or “generic types” are a development/compile-time feature that I like to think of as syntax to implement the strategy pattern. It involves building a template for a type that opens a new world of possibilities when the type is resolved. The resulting JavaScript doesn’t contain any notation or syntax, but as you will see in this video the use of generics can help quickly capture and fix defects before they are sent to production.
To simplify the code, a custom type is created that uses generics to define a predicate. You can think of a predicate as a test. Given an item T it returns either true or false. This type can then be used to define the second parameter in the find function. The result? Source code that is easier to read and maintain with no changes to the generated JavaScript.
Summary
This concludes part one. Hopefully by now you feel comfortable with TypeScript and can see some of its immediate benefits. Part Two tackles more advanced concepts, including interfaces, “key types,” type guards, strict typing, type decorators and what happens when you target different versions of JavaScript. (The link will be updated here when part 2 is available).