Chapter 1. From JavaScript to TypeScript

Before talking about TypeScript, we need to first understand where it came from: JavaScript!

History of JavaScript

JavaScript was originally designed in 10 days by Brendan Eich at Netscape in 1995 to be approachable and easy to use for websites. Developers have been poking fun at its quirks and perceived shortcomings ever since. I’ll cover some of them in the next section.

JavaScript has evolved tremendously since 1995, though! Its steering committee, TC39, has released new versions of the language consistently yearly since 2015 with new features that bring it in line with other modern dynamic languages. Impressively, even with regular new language versions, JavaScript has managed to maintain backwards compatibility for decades in varying environments, including browsers, embedded applcations, and server runtimes.

Today, JavaScript is a wonderfully flexible language with a lot of strengths. You and I should appreciate that while JavaScript has its quirks, it’s also helped enable the incredible growth of web pages and the internet.

Show me the perfect programming language and I’ll show you a language with no users.

Anders Hejlsberg, TSConf 2019

Vanilla JavaScript’s Pitfalls

Developers often refer to using JavaScript without any significant language extensions or frameworks as “vanilla”: referring to it being the familiar, original plain version. I’ll soon go over why TypeScript adds just the right flavor to overcome these particular major pitfalls, but it’s useful to understand just why they can be painful.

Costly Freedom

Many developers’ biggest gripe with JavaScript is unfortunately one of its key feature: JavaScript provides virtually no restrictions in how you structure your code. That freedom makes it a ton of fun to start a project in JavaScript! You can quickly write code in any which way and watch it magically work.

As you get to have more and more files, though, it becomes apparent how that freedom can be damaging. Take the following snippet, presented out of context from some fictional musical application:

function paintPainting(painter, painting) {
  return painter
    .prepare()
    .paint(painting, painter.ownMaterials)
    .finish();
}

Reading that code without any context, you can only have vague ideas how to use paintPainting. Perhaps if you’ve worked in the surrounding codebase you may recall that painter should be what’s returned by some getPainter function. You might even make a lucky guess that painting is a string.

Even if those assumptions are correct, though, later changes to the code may invalidate them. Perhaps painting is changed from a string to some other data type, or maybe one or more of the painter’s methods are renamed.

Other languages might refuse to let you run code if their compiler determines it would likely crash. Not so with JavaScript.

The freedom of code that makes JavaScript so fun becomes a real pain when you want safety in running your code.

Loose Documentation

Nothing exists in the JavaScript language specification to formalize describing what function parameters, function returns, variables, or other constructs in code are meant to be. Many developers have adopted a standard called JSDoc to describe functions and variables using block comments. The JSDoc standard describes how you might write documentation comments placed directly above constructs such as functions and variables, formatted in standard way. Here’s an example, again taken out of context:

/**
 * Performs a painter painting a particular painting.
 *
 * @param {Hero} painter
 * @param {string} painting
 * @returns {boolean} Whether painting was painted.
 */
function paintPainting(painter, painting) { /* ... */ }

JSDoc has key issues that often make it unpleasant to use in a large codebase:

  • It can be difficult during code refactors to find all the now-invalid JSDoc comments related to your changes

  • Nothing stops JSDoc descriptions from being wrong about code

  • Describing complex objects is unweildy, requiring multiple standalone comments to define types and their relationships

Weaker Developer Tooling

Because JavaScript doesn’t provide built-in ways to identify types, and the JSDoc standard is a suggestion that allows to code to easily diverge from comments, it can be very difficult to automate large changes to or gain insights about a codebase. JavaScript developers are often surprised to see features in typed languages such as C# and Java that allow developers to perform class member renamings or jump to the place an argument’s type was declared.

Note

You may protest that modern IDEs such as VS Code do provide some automated refactors to JavaScript. True, but: they use TypeScript to do so, and they’re not as reliable or as powerful as when refactoring well-defined TypeScript code.

TypeScript!

TypeScript was created internally at Microsoft in the early 2010s then released and open sourced in 2012. The head of its development is Anders Hejlsberg, notable for also having lead the development of the popular C# and Turbo Pascal languages. TypeScript is often described as a “superset of JavaScript” or “JavaScript with types”.

But what is TypeScript?

TypeScript is four things:

  • Programming language: a language that includes all the existing JavaScript syntax, plus new TypeScript-specific syntax for defining and using types.

  • Type checker: a program that takes in a set of files written in JavaScript and/or TypeScript, develops an understanding of all the constructs (variables, functions, …) created, and lets you know if it thinks anything is set up incorrectly.

  • Compiler: a program that runs the type checker, reports any issues, then outputs the equivalent JavaScript code.

  • Language services: a program that uses the type checker to tell editors such as VS Code how to provide helpful utilities to developers.

TypeScript in Action

Take a look at this code snippet:

const firstName  "Georgia";
const nameLength  firstName.length();
//                           ~~~~~~
// This expression is not callable.

The code is written in normal JavaScript syntax — I haven’t introduced TypeScript-specific syntax yet. If you were to run the TypeScript type checker on this code, it would use its knowledge that the length property of a string is a number -not a function- to give you the complaint shown in the comment.

If you were to paste that code into an editor with TypeScript support -meaning it runs the TypeScript language services for you-, it would be told by those language services to give you a little red squiggly under length indicating TypeScript’s displeasure with your code. Hovering over the squigglied code would give you the text of the complaint (Figure 1-1):

TypeScript reporting the 'length' property of a firstName string is not callable.
Figure 1-1. TypeScript reporting an error on string length not being callable.

Being told of these simple errors in your editor as you type them is a lot more pleasant than waiting until a particular line of code happens to have been run in the app and throw an error.

Freedom Through Restriction

TypeScript allows us to specify what types may be provided as values for parameters and variables. Some developers find having to explicitly write out in your code how particular areas are supposed to work to be restrictive at first.

But! I would argue that being “restricted” in this way is actually a good thing! By restricting our code to only being able to be used in the ways you specify, TypeScript can give you confidence that changes in one area of code won’t break other areas of code that use it.

If, say, you change the number of required parameters for a function, TypeScript will let you know if you forget to update a place that calls the function.

In the following example, sayMyName was changed from taking in two parameters to taking one parameter, but the call to it with two strings wasn’t updated and so is triggering a TypeScript complaint:

// Previously: sayMyName(firstName, lastNameName) { ...
function sayMyName(fullName) {
  console.log(`You acting kind of shady, ain't callin' me ${fullName}`);
}

sayMyName("Beyoncé", "Knowles");
//                   ~~~~~~~~~
// Expected 1 arguments, but got 2.

Precise Documentation

Let’s look at a TypeScript-ified version of the paintPainting function from earlier. Although I haven’t yet gone over the specifics of TypeScript syntax for documenting types, the following snippet still hints at the great precision with which TypeScript can document code:

interface Painter {
  finish(): boolean;
  ownMaterials: Materials;
  paint(painting: string, materials: Material[]);
}

function paintPainting(painter: Painter, painting: string) { /* ... */ }

A TypeScript developer reading this code for the first time could understand that painter has at least three properties, two of which are methods. By baking in syntax to describe of the “shapes” of objects, TypeScript provides an excellent, precise method for describing how objects look.

Stronger Developer Tooling

TypeScript’s precise typings allow editors such as VS Code to gain a much deeper insight into your code, which they then use to surface intelligent suggestions as you type. These suggestions can be incredibly useful for development.

To start, if you’ve used VS Code to write JavaScript before, you might have noticed that it suggests “autocompletions” as you write code with built-in types of objects like strings (Figure 1-2):

TypeScript suggesting a dropdown of properties starting with 'se' as members of a string.
Figure 1-2. TypeScript providing autocompletion suggestions in JavaScript for a string.

When you add TypeScript’s type checker for understanding code, it can give you these rich suggestions even for code you’ve written. If start typing painter. in the paintPainting function, TypeScript would take its knowledge that the painter parameter is of type Painter and the Painter type has the following members (Figure 1-3):

TypeScript suggesting a dropdown of three predefined properties as members of the Hero type.
Figure 1-3. TypeScript providing autocompletion suggestions in TypeScript for a custom type.

Snazzy!

What TypeScript Is Not

Now that you’ve seen how awesome TypeScript is, before you give it a test drive, I have to warn you about some limitations. It’s still a very fantastic piece of technology but it’s important to check expectations regarding what TypeScript is, and isn’t. As with every tool, it excels at some areas and has limitations in others.

A Remedy for Bad Code

TypeScript helps you structure your JavaScript but other than enforcing type safety it doesn’t enforce any opinions on what that structure should look like.

Good!

TypeScript is a language that everyone is meant to be able to use, not an opinionated framework with a target audience.

If anybody tries to tell you that TypeScript forces you to use classes, or makes it hard to write good code, or whatever code style complaints are out there, give them a stern look and tell them to pick up a copy of Learning TypeScript. TypeScript does not enforce code style opinions such as whether to use classes or functions.

Extensions to JavaScript (Mostly)

TypeScript’s design goals explicitly state that it should:

  • Align with current and future ECMAScript proposals.

  • Preserve runtime behavior of all JavaScript code.

TypeScript does not change how JavaScript works at all. Its creators have tried very hard to avoid adding new code features that would add to or conflict with JavaScript. Such a task is the domain of TC39, the technical committee that works on ECMAScript itself.

There are a few older features in TypeScript that were added many years ago to reflect common use cases in JavaScript code. Most of those features are either relatively uncommon, have fallen out of favor and are only covered briefly in Appendix ??. I recommend staying away from them in most cases.

Slower Than JavaScript

Sometimes on the internet, you might hear some opinionated developers complain that TypeScript is slower than JavaScript at runtime. That claim is generally misleading and inaccurate: TypeScript doesn’t introduce any runtime complexity to code, so running code compiled from TypeScript can’t be inherently slower!

TypeScript does, however, add some time to building your code. TypeScript code must be compiled down to JavaScript before most environments, such as browsers and Node.js, will run it. Most build pipelines are generally set up so that the performance hit is negligible, and expensive TypeScript-only operations are done separately from truly building code to be run.

Warning

Even projects that seemingly allow running TypeScript code directly, such as ts-node and Deno, themselves internally convert TypeScript code to JavaScript before running it.

Finished Evolving

The web is nowhere near finished evolving, and thus neither is TypeScript. The TypeScript language is constantly receiving bug fixes and feature additions to match the ever-shifting needs of the web community. The basic tenets of TypeScript you’ll learn in this book will remain about the same, but error messages, fancier features, and editor integrations will improve over time.

In fact, while this edition of the book was published with TypeScript version 4.3.5 as the latest, by the time you started reading it we can be certain a newer version has been released. Some of the TypeScript error messages in this book might even already be out of date! Thanks, Anders.

Getting Started in the TypeScript Playground

You’ve read a good amount about TypeScript by now. Let’s get you writing it!

The main TypeScript website includes a “playground” editor at https://www.typescriptlang.org/play. You can type code into the main editor and see many of the same editor suggestions you would working with TypeScript locally in a= full IDE.

Most of the snippets in this book are intentionally small and self-contained enough that you could type them out in the playground and tinker with them for fun.

Compiling Syntax

TypeScript’s compiler allows us to input TypeScript syntax, have it type checked, and get the equivalent JavaScript emitted. As a convenience, the compiler will also take modern JavaScript syntax and compile it down into its older ECMAScript equivalents.

If you were to paste this TypeScript code into the playground:

const warrior = "Kahina";
console.log({ warrior });

The playground would show you on the right-hand-side of the screen that this would be the equivalent JavaScript output by the compiler:

"use strict";
var warrior = "Kahina";
console.log({ warrior: warrior });
Note

Many JavaScript projects use a tool called Babel (https://babeljs.io) for this same purpose. Babel does have great TypeScript tooling, though I don’t cover it until Chapter ??.

Getting Started Locally

To install the latest version of TypeScript globally on your computer, run the following command:

npm i -g typescript

Now, you’ll be able to run TypeScript on the command-line with the tsc (TypeScript Compiler) command. Try it with the --version command to make sure it’s set up properly.

tsc --version

It should print out something like Version X.Y.Z — whichever version is current as of you installing TypeScript.

Running Locally

Now that TypeScript is installed, let’s have you set up a folder locally to run TypeScript on code. Create a folder somewhere on your computer - for my commands, I’ll assume the path /code/learning-typescript - and run this command to create a new tsconfig.json configuration file:

tsc --init

A tsconfig.json file declares the settings that TypeScript uses when analyzing your code. Most of the options in that file aren’t going to be relevant to you in this book (there are a lot of uncommon edge cases in programming that the languages need to account for!). I’ll cover them in Chapter ??.

The important feature is that now you can run tsc to tell TypeScript to compile all the files in that folder.

Try adding a file named index.ts with the following contents:

console.blub("Hello world!");

Then, run tsc.

tsc

You should get an error that looks roughly like:

index.ts:1:9 - error TS2339: Property 'blub' does not exist on type 'Console'.

1 console.blub("Hello world!");
          ~~~~

Found 1 error.

Indeed, blub does not exist on the console. What was I thinking?

Before you fix the code to appease TypeScript, note that tsc created an index.js for you with contents including the console.blub.

Note

This is an important concept to reflect on: even though there was a type error in our code, the syntax was still completely valid. The TypeScript compiler was able to produce valid JavaScript from the input file’s valid syntax regardless of the type error.

Correct the code in index.ts to call console.log and run tsc again. There should be no complaints in your terminal, and the index.js file should now contain updated output code.

"use strict";
console.log("Hello, world!");

Editor Features

Another benefit of creating a tsconfig.json file is that when editors are opened to a particular folder, they will now recognize that folder as a TypeScript project. For example, if you open VS Code in the same folder through its GUI or with its terminal command:

code .

(alternately, code /code/learning-typescript)

The settings it uses to analyze your TypeScript code will respect whatever’s in the tsconfig.json file it sees in that folder.

As an exercise, go back through the code snippets in this chapter and type them in your editor. You should see dropdowns suggesting completions for names as you type them, especially for members such as the log on console.

Very exciting: you’re using the TypeScript language services to help yourself write code! You’re on your way to being a TypeScript developer!

Tip

VS Code comes with great TypeScript support. Many TypeScript and/or web developers use VS Code as their primary editor — myself included. You don’t have to use it for TypeScript, but I do recommend it for at least trying out TypeScript while reading through this book.

Summary

In this chapter, you read up on the context for some of JavaScript’s main weaknesses and how TypeScript helps with:

  • The history of JavaScript

  • JavaScript’s pitfalls: costly freedom, loose documentation, and and weaker developer tooling

  • TypeScript’s advantages: freedom through restriction, precise documentation, and stronger developer tooling

  • What TypeScript is not: a remedy for bad code, extensions to JavaScript (mostly), slower than JavaScript, or finished evolving

  • Getting started writing TypeScript code on the TypeScript playground and locally on your computer

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.107.96