Getting Started With TypeScript

Getting Started With TypeScript#

Introduction#

TypeScript helps us write large applications by introducing static types to JavaScript.

JavaScript was designed to be accessible to an audience of developers and non-developers alike. It was meant to be approachable and easy for beginners to pick up. This ultimately resulted in a language that is great for developing prototypes and medium-sized projects. But when it comes to building large applications, JavaScript development is difficult to scale, largely because we are unable to define explicit contracts between the components that make up our application.

Static vs. Dynamic Typing#

The difference between static and dynamic typing has to do with when the types of the written program are checked. In statically-typed languages (TypeScript), types are checked at compile-time. In dynamically-typed languages (JavaScript), types are checked at run-time.

Microsoft introduced TypeScript in 2012 to solve the scalability problems with JavaScript development. In TypeScript, types are optional by default to ease integration with existing projects, and JavaScript developers are able to quickly learn the basics of TypeScript as it builds on top of a familiar language.

TypeScript has continued to rise in popularity since its initial release. To quote some recent numbers:

We begin this chapter by exploring two fundamental questions:

  1. What is TypeScript?

  2. Why Should I Use TypeScript?

We will also build a small library that will expose us to practical examples of using TypeScript to solve real-world problems. By the end of the chapter, we'll have a solid understanding of what TypeScript is, why we should use it, and how it is used in practice.

What is TypeScript?#

TypeScript is a superset (or extension) of JavaScript that provides optional static types. Being a superset of JavaScript means that valid JavaScript is also valid TypeScript.

Types are stripped away during a compilation process that transforms TypeScript code into valid JavaScript. The compiled JavaScript is compliant with ES3 (ECMAScript 3) by default, but can be configured to compile down to newer versions, including ES2015 through ES2017.

What this jargon means is that TypeScript gets compiled down to "regular" JavaScript and your browser runs JavaScript. Put another way, your browser doesn't know how to run "TypeScript" per-se, instead we run a program that "converts" our TypeScript into JavaScript our browser (or Node.js, but let's not get ahead of ourselves) can understand.

ECMAScript#

ECMAScript is the language specification that JavaScript is based on, and beginning with ES2015, a new version of ECMAScript is published every year using a naming convention that contains the year the spec is finalized: ES2015 for the spec finalized in 2015, ES2016 for the spec finalized in 2016, and so on. By the time a new spec is published, JavaScript runtimes (i.e. browsers and Node.js) will have already implemented a majority of the new features.

The diagram below shows the relationship between TypeScript, ES5, ES2015+, and ESNext:

ES5, ES2015+, ESNext, and TypeScript

TypeScript supports ES5 and ES2015+ specs, but it does not support all ESNext features, which are features that are still making their way through the ECMAScript approval process. Two examples of this (at the time of writing) are the optional chaining operator and private class fields--two features which are available in most modern browsers.

The takeaway from the diagram is that you should double check before using cutting-edge features that would otherwise be available in vanilla JavaScript. You can visit the TypeScript repo on Github and search through the issues to see if a new feature is available for use.

ECMAScript 2015#

The introduction of ECMAScript 2015 (commonly referred to as ES6) marked a new era for JavaScript development by introducing important features to the language, including:

Classes const / let declarations Arrow functions Promises Modules Generators Iterators Object destructuring* Spread operator

Every feature listed above is available in TypeScript, and we'll see them used throughout the book. See Appendix A: ES2015 for an in-depth look at the features introduced in ES2015.

Not only does TypeScript support most ECMAScript features, it also introduces a syntax for annotating types.

JavaScript vs. TypeScript Example#

Let's look at an example.

The code below, written in ES5-compliant JavaScript, attempts to log a greeting message. The logGreeting function accepts a string message and logs a greeting message constructed using the input string:

Untyped JavaScript#

JavaScript is valid TypeScript, so the code above will pass through the TypeScript compiler without errors -- despite the incorrect usage of logGreeting, where an object is passed to the function as opposed to a string.

Key Idea: JavaScript is valid TypeScript

Running the code in any environment will produce an output similar to:

But displaying Object in our log isn't what we want! Instead, we'd like to only allow a string to be passed as the message argument. If an object is passed to the function, we'd like to reject that value and require that a string is passed instead.

One potential solution is to add an if-statement that checks the type of the argument passed and throw an error if that type is not a string. Although this seemingly solves the problem, we won't see the error until we run the code, and this solution will be hard to scale for more complicated types, such as an object containing a specific set of values.

Catching Errors with Types#

With TypeScript, we can catch these errors without having to run the code, and if you are using an IDE with TypeScript support, you'll receive this feedback in real-time as you type.

We add a type annotation to logGreeting to specify that the function only accepts strings:

By specifying that message should be a string, we'll get the following error when compiling the code:

Despite the error, TypeScript will emit valid JavaScript by default. It's a good idea to disable this behavior to minimize the possibility of publishing buggy code, but we won't worry about modifying compiler settings for now. We'll discuss best practices for configuring the compiler in a later section.

To fix the error, we need to pass a string to logGreeting. The correct usage is to pass person.name to the function:

This will compile without errors, and the new output of the function will be the expected greeting message:

Why Should I Use TypeScript?#

TypeScript helps us achieve the following:

  • Easier refactoring: we are able to easily change the modules and functions in our application with confidence that errors arising from those changes will be exposed at compile-time.

  • Intelligent code completion: our code editors are able to provide auto-complete functionality for the objects that are used in the application.

  • Early bug detection: typos, missing parameters, and mismatched types are examples of bugs that will be caught at compile-time.

  • Documentation: type annotations are great sources of documentation as they describe the inputs/outputs of functions and the structure of data in your application.

These benefits are helpful for projects of all size, but TypeScript also comes at a cost. You'll have to keep the following in mind when choosing TypeScript:

  • Learning curve: your team will have to invest time in learning TypeScript. It's important that every developer on the team is able to maintain and update types accurately.

  • Extra build step: you will have to configure TypeScript with your current build system, and depending on the size of the project, this build step could add several seconds to the total build time.

  • Third-party libraries: you will have to ensure that the third party libraries you are using have types that are up-to-date, which is usually not a problem for popular libraries, but smaller, more obscure libraries might have types that are nonexistent out of date. In later chapters we cover how to get around libraries that are not typed.

  • Integration period: when integrating TypeScript with an existing project, the adoption should happen incrementally, meaning there will be a period where you will have to maintain JavaScript and TypeScript files at the same time.

Over time the benefits will outweigh the cons as the penalty for choosing TypeScript is mostly fixed at the adoption point, and third-party support will improve as TypeScript's popularity continues to rise.

Please select a discussion on the left.