TypeScript for JavaScript Developers by Refactoring Part 1 of 2
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.
This is a two-part series. You can jump to part 2.
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.
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.
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.
🔗 Learn more about the tsconfig.json
file
🔗 Learn more about “rest parameters”
3. Classes and Types
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.
🔗 Learn more about basic types
🔗 Learn more about classes
4. Custom Types
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.
🔗 Learn more about custom types
5. Scope and the “let” Keyword
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.
🔗 Learn more about let declarations
6. Lambda Expressions
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.
🔗 Learn more about “this” and arrow functions
7. String Templates
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.
🔗 Learn more about string templates
8. Generic Types
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.
9. Custom Types with Generics
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.
Regards,