New Sep 6, 2024

A Complete Guide to Beginning with TypeScript

More Front-end Bloggers All from Frontend Masters Boost RSS Feed View A Complete Guide to Beginning with TypeScript on frontendmasters.com

This guide is not itself the means to learn TypeScript. This guide addresses issues around getting started (obstacles, preliminary knowledge, etc.) and then points you to curated resources to start learning. Consider this material a prologue or an introduction to the learning process itself so, you have the needed background and context before beginning the learning process.

Prerequisite Knowledge

The list below briefly highlights the knowledge needed before learning TypeScript:

Helpful Background on TypeScript

Why Learn/Use TypeScript?

Today, most developers who professionally use JavaScript to build software use TypeScript. They do so for the following reasons: By learning TypeScript and learning it well, you’ll better understand the complicated parts of JavaScript, which will make you a better JavaScript developer.

Getting Started with TypeScript Obstacles

Steep Learning Curve

Adding on TypeScript can be extremely overwhelming both academically and in practice. This is especially true for those just learning JavaScript as well as those who are seasoned JavaScript developers.

More Rules, More Errors

TypeScript adds additional rules to the JavaScript language regarding data types and will throw a TypeScript error when JavaScript does not. This can be a bit confusing and frustrating. It can’t be stated enough that TypeScript is bossy and a bit messy, especially if TypeScript expects that all values avoid the any type.

More Code, More Development Time/Management

TypeScript type annotations are nonstandard syntactical overhead. It adds more lines of code to your files (i.e., type annotations) and more files (i.e., type declarations) to your code base. It is simply more information to take in and manage. Given a large code base authored and maintained by developers of differing skills, this may be ideal. But it does have a cost. Grokking TypeScript and TypeScript annotations and appeasing the TypeScript compiler can be frustrating, daunting, and time-consuming.

The fact is, that TypeScript takes more time and adds lines of complexity. Many teams believe the value provided to be worth the overhead. The cost of implementation vs. the value provided is a complicated equation with many variables. How developers evaluate this equation often will say more about the developers than it says objectively about code quality, code durability, or code longevity.

A Compiler Step

While most professionals are already accustomed to the tooling/building processes that modern JavaScript development requires TypeScript is a far cry from simply writing some code that is executed by a web browser by way of a script element. TypeScript comes with the overhead of compiling it to standard JavaScript.

Top Use Cases of TypeScript

The following four use cases for TypeScript overlap and extend the reasons why a developer might choose to learn TypeScript:

Let’s examine each of these use cases in more detail.

Typescripts Type System Brings Strongly Typed Enforceable Mechanics to JavaScript

TypeScript is most well-known for its type system. I’ll briefly explain the tenants and implications of this system so that one can minimally begin to understand its value.

To review, the JavaScript language has eight types of values that can be used by the language:

  1. Boolean
  2. null
  3. undefined
  4. Number
  5. BigInt
  6. String
  7. Symbol
  8. Object

Behind the scenes, JavaScript dynamically assigns one of these types to JavaScript values and will transparently allow reassignment and coercion of these types. TypeScript’s main objective is to change this aspect of JavaScript.

In the code example below, I’m using several JavaScript data types (i.e., Strings, Objects, and a Number):

let firstName = "Sally";
let lastName = "Brown";
let age = 25;

let user1 = {
  firstName: "Bill",
  lastName: "Fae",
  age: 45,
};

const getFullName = (user1) => {
  return `${user.firstName} ${user.lastName}`;
};

console.log(getFullName(user)); // logs "Bill Fae"

Without TypeScript, JavaScript would have no problem if we decided to change the value of age from a number to a string. Or if we decided to change the shape of the user object by adding a new property to the user Object called middleName. JavaScript would also be ok if we passed the getFullName() function an empty object, until the code is run.

However, by using TypeScript and its type system, we can add type annotations to JavaScript that will make JavaScript act more like a programming language that does not allow type reassignment, changes, and JavaScript runtime errors.

Below I am taking the previous code and adding all possible TypeScript type annotations to the JavaScript. You should carefully contrast this code to the previous code with no type annotations.

let firstName: string = "Sally";
let lastName: string = "Brown";
let age: number = 25;

// define the shape of a user object before defining a user object
interface UserTypeInterface {
  firstName: string;
  lastName: string;
  age: number;
}

// define a user, annotate user with a type interface
let user1: UserTypeInterface = {
  firstName: "Bill",
  lastName: "Fae",
  age: 45,
};

// create a function, that only accepts values matching our UserTypeInterface,
// also, define what should be returned from this function
const getFullName = (user1: UserTypeInterface): string => {
  return `${user.firstName} ${user.lastName}`;
};

console.log(getFullName(user)); // logs "Bill Fae"

By using TypeScript type annotations, we have layered a degree of control over our JavaScript, which enforces patterns from strongly typed languages. For example, I can no longer change the type of value that age can contain, or the shape of the user object, or create a function that will accept any type of value. What JavaScript would permit in our program is not permitted when using TypeScript. In the video below you will see that TypeScript reports issues where JavaScript does not.

 

The example above, where I explicitly provided all possible type annotations, is a bit contrived because explicitly providing all possible type annotations is verbose and ignores the fact that the type system can perform type inference and infer certain types without explicit annotations.

 

The type system can infer a lot, but it does not infer everything needed to take full advantage of TypeScript. Most developers use inference where they can and then provide additional annotations where needed. In the code below, a mixture of inferences and annotations are used, which is likely closer to the reality of developing TypeScript in the wild.

let firstName = "Sally"; // simple values can be infered
let lastName = "Brown"; // simple values can be infered
let age = 25; // simple values can be infered

// this is done so that the shape of this object is required
// the shape of an object can't be infered, we have to define it
interface UserTypeInterface {
  firstName: string;
  lastName: string;
  age: number;
}

let user1: UserTypeInterface = {
  firstName: "Bill",
  lastName: "Fae",
  age: 45,
};

// explicitly tell this function the exact shape of the value passed in
// without this, the value passed into the fuction is given a type of any
// which depending upon how you configure TypeScript will throw an error
const getFullName = (user1: UserTypeInterface) => {
  // infer the return type
  return `${user.firstName} ${user.lastName}`;
};

console.log(getFullName(user)); // logs "Bill Fae"

We have only scratched the surface of the type system and type annotations in TypeScript. Imagine if you needed optional values. Or values that are of a limited specific value only. TypeScript can do all that and much more.

As a small and simple example in the code below, I am telling TypeScript that the User object has an optional age property and a property called group with a fixed set of potential property values.

interface UserTypeInterface {
  firstName: string;
  lastName: string;
  // used ?:, property is not required, but if it is provide has to be number
  age?: number;
  group: "blueTeam" | "redTeam"; // has to be "blueTeam" or "redTeam"
}

let user1: UserTypeInterface = {
  firstName: "Bill",
  lastName: "Fae", // age is optional
  group: "blueTeam",
};

The takeaway here should not be an in-depth understanding of the type system or annotations. I’m only trying to communicate broadly the point of the type system and roughly what it fundamentally provides above and beyond JavaScript.

TypeScript Reports JavaScript Syntax Errors as well as TypeScript Type Errors

TypeScript not only reports issues found by the type system, but it can also report JavaScript syntax errors that will occur during runtime. By using TypeScript, these errors can be surfaced before runtime.

The code in the video below is filled with JavaScript syntax errors which TypeScript will report on.

 

TypeScript & VS Code Provide a Superior Authoring Environment for JavaScript

Developers use TypeScript because it can convert the language into a language that mimics strongly typed languages by way of the type-system while also reporting JavaScript syntax errors without manually executing the JavaScript. However, it’s not until these two aspects of TypeScript are combined with TypeScript development tools these merits become objective benefits.

If a developer has the TypeScript compiler installed, then development environments like VS Code become objectively better in the following ways (click on the links and read the explanations in the VS code documentation):

TypeScript Can Compiling Current and Next Generation ECMAScript to Older ECMAScript

To review, TypeScript can:

  1. Convert JavaScript into a language that resembles a strongly typed language.
  2. Preemptively notify you of JavaScript syntax errors while authoring.
  3. Integrate into VS Code and provide a superior development environment for authoring and maintaining code written in JavaScript.

Lastly, it can take the most current ECMAScript specifications, as well as ECMAScript proposals (i.e., next-generation JavaScript), and compile it into older versions of JavaScript. This allows developers to make use of the most current and even futurist parts of JavaScript today but support much older runtimes that might not support current and futurist parts of JavaScript.

Before Learning Starts

We suggest becoming familiar with the following before you begin hands-on learning:

Start Learning

Here is a three-step topical outline including learning resources to facilitate learning TypeScript:

You must spend enough time in Step 1 before moving to Step 2. If you are intimidated or struggling with Step 2, return to Step 1 and spend more time with the fundamentals.

Step 1 – Introductory TypeScript

Video Courses:

Reading Material:

Exercises:

Step 2 – TypeScript Intermediate to Advanced Concepts

Video Courses:

Reading Material:

Exercises:

Step 3 – TypeScript & Friends

Video Courses:

Commonly Asked Questions

Should I learn JavaScript and TypeScript at the same time?

If you are new to programming, JavaScript should be isolated and learned before learning TypeScript. TypeScript has a steep learning curve, steeper than JavaScript itself. Understanding both of these at the same time can be overwhelming. Before you approach TypeScript, learn JavaScript in-depth! Especially the fact that JavaScript is a dynamic and weakly typed language.

Is TypeScript itself a programming language?

TypeScript is not a programming language itself. JavaScript is the programming language that TypeScript requires to be considered a programing language. When one suggests that TypeScript is a programming language, they are undoubtedly trying to communicate the belief that type annotations are a language. The type-annotation syntax intermingles with JavaScript syntax at development time. It is technically not a language without JavaScript. That is why “a superset of JavaScript” or “JavaScript with types” are the phrases used to describe TypeScript.

This is JavaScript:

let count = 2;

This is JavaScript with a simple TypeScript type annotation (i.e., : number):

let count: number = 2;

The programming language in question is still JavaScript, even though a TypeScript type annotation is being added to the JavaScript.

What is the TypeScript Compiler?

The TypeScript compiler (aka, tsc) is a Node.js CLI tool that can:

  1. Compile/transpile TypeScript to JavaScript.
  2. Statically analyze the validity of Typescript and JavaScript based on TypeScript rules, configurations, and type annotations or the lack thereof (can also be used by code editors to provide this information as you author JavaScript + TypeScript annotations).

To gain a basic understanding of the compiler, I’m going to walk us through a simplistic use of the tsc Node.js CLI tool.

Go to StackBlitz and create a new Node.js project by clicking on “Node.js Blank project” at the top of the screen. You should be looking at a new Node.js project in your browser window.

Go to the terminal of the StackBlitz project you just created and type the following in the terminal, and hit enter:

npm i typescript

This will install TypeScript and the tsc CLI tool into the StackBlitz Node.js project.

You should be looking at something similar to this:

With TypeScript now installed initialize a TypeScript project by creating a .tsconfig from running:

tsc --init

This will add a “tsconfig.json” file that is used to configure the TypeScript compiler. Open the “tsconfig.json” file and find and change “target”: “es2016” to “target”: “es5”. Save this file.

Next, change the extension of the “index.js” file to “index.ts”. And replace the contents of the file with:

let count: number = 2;

Save the file and now let’s use the TypeScript compiler (i.e., tsc) to type check and compile/transpile the “index.ts” file to JavaScript.

In the terminal run:

tsc index.ts

This will create a new file called “index.js”. Open the “index.js” file and take note that the compiler removed the TypeScript type annotation “: number” and change “let” to “var” (Note that “let” was not yet supported in ES5).

Next, let’s purposely create a TypeScript error so we can see the compiler report a type issue.

Replace the contents of the “index.ts” file with:

let count: string = 2;

Save this file.

TypeScript will certainly have an issue with this because the data type of 2 is not a string but a number.

Now run the compiler again using:

tsc index.ts

Note that both the code editor (red squiggly line under “count”) and the “tsc” CLI tool are reporting a TypeScript error.

In this short exercise, we used the TypeScript compiler to compile/transpile TypeScript to JavaScript and took note of the type-checking capabilities of the compiler as well as the editor.

What is Type Checking?

Type checking is the process of analyzing TypeScript syntax for TypeScript soundness based on TypeScript configurations as well as TypeScript type annotations or lack thereof.

This process can occur when compiling/transpiling using the “tsc” CLI tool or when authoring TypeScript code. For example, code editors like VSCode (via the language service) can use the TypeScript compiler in the background to perform type-checking in real-time:

Most developers use their code editor to do type checking in real-time and then use build tools to transpile “.ts” and “.tsx” files to “.js” files. For example, out of the box, Vite will compile both “.ts” and “.tsx” files to JavaScript files but not perform type checking. It leaves that up to the code editor.

What’s Next?

After reading this guide and consuming the learning material a possible next step would be to investigate the following tools that often go hand and hand with TypeScript:

Make sure to check out the learning path on TypeScript.

Scroll to top