TypeScript Accelerated

The Accelerated series embraces new technologies to allow you to learn with interactive learning Apps and other resources like books, quizzes and more. They aim to overcome the 'Google Effect' (I can Google it so my brain doesn't even try to retain it) and achieve genuine fluency with Modern Software Development technologies.

Apps

The primary form of TypeScript Accelerated is the App. Out now for iPhone and iPad.

But on this site you can also find:

Sample Chapters

Below are a few chapters from the book.

Introduction

It is an almost impossible task to write a great book on programming. It requires not just skill and effort on the part of the author, but a rare alignment of experience, aptitude and interest with the reader. A dry reference is possible but of limited value. A tutorial unlikely to be pitched at the right level. This book tries something different in its goal of teaching TypeScript. In that it is not primarily a book. It is primarily a Flash Card App.

It focuses on the most useful details. You absolutely should work through real examples, but these should come from the demands of your own project(s) or failing that in a structured, challenge based way (I recommend sources for these). It targets fluency not superficial knowledge, but includes the hard parts and tools to make learning them reasonable. I want to make it possible for you to learn TypeScript more quickly and more thoroughly than has otherwise been possible.

Audience

Ideally you would already know some Javascript. The focus will be on the features TypeScript adds to Javascript. However if you know languages like Java or C# you shouldn't have too much trouble.

Typescript

Javascript is the most popular programming language in the world by most measures. It has incredible reach: from webpages to servers, to native mobile apps and IOT devices. It is easy (at least to get started). It is surprisingly performant. It is flexible. And it is also (in some respects) terrible, constrained by its legacy and superficially worse than most programming languages (apart from PHP).

But it is getting better. The language has rapidly evolved. It has incredible frameworks for user interfaces, testing, web servers and data visualisation. It has an incredible range of open source libraries and frameworks (all easily accessible via NPM). And on top of its flawed foundations tooling has addressed many of the worst issues. This is where TypeScript comes in.

TypeScript provides additional syntax on top of Javascript, allowing us to declare types and use features like generics and annotations that you may have seen in other languages. But it does this in a way that is a very Javascripty way, indeed working with TypeScript is likely to give you a clearer understanding of Javascript's type system. With this extra information development becomes easier and safer as our editor or IDE is more able to give us information or suggest completions. It also makes it easier to work with other people (or to work with our own code from a few months ago).

But it works with 'legacy' Javascript code as we can use type definitions to help (even where the code is vanilla Javascript). Indeed TypeScript's approach is by far the most popular and type definitions are available for pretty much all popular Javascript libraries.

Technically TypeScript is an optional typing system, but in practice it encourages us to statically type the great majority of our code and allows us the escape hatch of dynamic typing when it is needed.

How to use this book

This book consists of lots of concise chapters, each with a small number of core ideas. Most focus on a topic and give a concise but clear description. Ideally you would mainly use the Flash Card App to drive learning from this book, looking up things you are struggling with. On the Accelerated website you will find more resources on TypeScript and other technologies.

For more comprehensive documentation see The Official TypeScript Documentation. This book/App focuses on the core things you need to know to be productive, but we leave out some minor or less used parts of the language.

In the next chapter we look at how to set up TypeScript. You might actually want to skip ahead and come back to this later, but I think it is important to see how easily TypeScript can be added to a wide variety of projects.

Functions

Function Types

Functions, again, build on modern Javascript, offering support for typing of regular and arrow functions and default arguments. For example

function reverse(s: string): string {
  return s.split("").reverse().join("");
}

reverse("java"); // "avaj"

const f = (x: number, y: number): number => x + y;

f(4,5); // 9

It is typically reasonable to define types for all the input parameters to a function but let TypeScript infer the output type(s), at least in simple cases like the above.

function reverse(s: string) {
  return s.split("").reverse().join("");
}

const f = (x: number, y: number) => x + y;

Advanced Function Typing

For default arguments we just add = value.

const f = (x: number, y: number = 1) => x + y;
f(2); // 3

We can also have an arbitrary number of same-typed parameters (rest parameters) with a ... before the final declared parameter. Like:

const g = (...ns: number[]) => ns.sort();  

Notice how the type is an array type. This allows you to do things that you might do with the horrendous-yet-flexible arguments pseudo-keyword in Javascript.

Types

We have seen basic types for primitives, collections and functions. And this is what you should try to use as much as possible. But TypeScript has some fancier types and ways of combining types that allow us to be more specific, more flexible or (if necessary) effectively ignore typing.

Empty and Nullable Types

null was called a billion dollar mistake by its creator (almost certainly a massive underestimate). Javascript unusually has (effectively) two different null values: null and undefined. TypeScript allows you to use both of these as types or use void to mean either. If a function doesn't return a value it returns undefined (this is a Javascript thing).

These types aren't very useful on their own (at least to declare variables). They may be the return type of a function, although there we are likely just to leave off the type. Where it gets more interesting is via nullable types, when a value can either be null/undefined. For example:

let s : null | string = maybeString();

Now TypeScript will try to ensure we handle the case where s is a string or null. This is an example of a union type, which we will return to later.

any Type

TypeScript offers any as an escape hatch. If a variable is of type any then TypeScript will assume you know what you are doing. Generally you should use these as little as possible. It will make your code much harder to reason about and very difficult to maintain or change. Your colleagues or future self might not forgive you for it.

Type Assertions

The other common way to tell TypeScript that you know better than it does is with a type assertion. There are two syntaxes for this, using angle brackets and as.

let letters = (<string>something).split("")
let letters = (something as string).split("")

never Type

You can explicitly declare a never return type for functions that never return (e.g. throw exceptions or have infinite loops).

Type Aliases

We can give a name to a type by using type:

type Label = string;
type Result = [ boolean, string ];

Right now this isn't so useful but it is standard for both object types and for union types. The two things we are about to look at.

Object Types

We can define object types by declaring each property wrapped in curly brackets (so it looks like the object itself). For example:

type Name = { first: string, last: string };
type Person = { name: Name, age: number, partnerName?: Name };

let me: Name = { first: "James", last: "Porter" };
me.last; // "Porter"

As you can see it is possible to nest these. We can also have nullable fields by using a ?.

Union Types

When a variable might be of multiple types we can use union types with a | to separate options. We have already seen

let s : null | string = maybeString();

But we can actually be more specific. For example we might model state of part of an app with:

type State = "loading" | "loaded" | "error"; 

Now Typescript will check that the value is actually one of these three specific strings (this is a string literal type, but you can also have literals of the other primitive types). This can be used within more complex types, like Objects or Tuples.

Union types become really useful when the objects can be distinguished, for example if each type has a fixed value for one property. Then we can do switch statements over the object allowing for very clear, concise and safe code (it is close to pattern matching in functional programming languages). This is called a discriminated union. For example:

type AppState = { state: "loading" } | { state: "loaded", data: string } | { state: "error", error: string }

const printState = (s: AppState) => {
  switch(s.state) {
    case "loading":
      return "Loading";
    case "error":
      return `Error: ${s.error}`;
    case "loaded":
      return `Loaded this data: ${s.data}`;
  }  
}

Generics

Javascript will happily work with very different kinds of variables, often converting them to what it thinks you mean (sometimes with almost pathologically terrible outcomes). In TypeScript we try to be more specific so as to avoid bugs and make refactoring more straightforward. But we would still like to be able to write general purpose code. Generics is a key tool for accomplishing this.

Let's consider how we might create a plus function. We can do

function plus(x: any, y:any):any { return x + y }

Indeed this is effectively the 'Javascript' approach. But we would typically want to only add two things together if they are of the same type. The syntax is simple (indeed the same as many other languages such as Java).

function plus<T>(x: T, y:T):T { return x + y }

Now we can use plus to add any two things of the same kind together. While this might still not work, it is a lot better than vanilla Javascript and will catch many errors. Indeed TypeScript actually treats the regular + operation in this way. Note that you can't (without weird hacks) have generic arrow functions. (A potential point of confusion: Flow does allow this.)

The syntax is also the same as we saw before for asserting types.

let letters = (<string>something).split("")

Okay so where might we actually create Generics? Actually, unless you are creating a library you may find that you are mostly a consumer of generic code. Using it for operations on collections or, what we see in the next chapter, when extending classes. For example one way of declaring arrays is: Array<T>.

Resources

Accelerated website

From the Introduction chapter of TypeScript Accelerated

The Official TypeScript Documentation

From the Introduction chapter of TypeScript Accelerated

Guide to TypeScript Declaration Files

From the Getting Started chapter of TypeScript Accelerated

ts-node

From the Getting Started chapter of TypeScript Accelerated

TypeScript Playground

From the Next Steps chapter of TypeScript Accelerated

Guide to differences between Flow and TypeScript

From the Next Steps chapter of TypeScript Accelerated