TypeScript: JavaScript + Types = Awesome Developer Productivity
Tags: typescript, javascript, webdev
Published: 2019-01-17 20:28:43

---
title: TypeScript: JavaScript + Types = Awesome Developer Productivity
published: true
description: TypeScript is a superset of JavaScript that adds type annotations and, thus, static typing on top of JavaScript. Learn how TypeScript can improve your developer productivity. In this part of the series we setup a simple TypeScript project and test some of the cool features of TypeScript. 
tags: [typescript,javascript,webdev]
canonical_url: https://www.barbarianmeetscoding.com/blog/2017/08/17/typescript-javascript-and-types-equal-awesome-developer-productivity/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/etq2lbyqso72wuhvmkft.png
---

*This article is a chapter from [JavaScript-mancy OOP: Mastering the Arcane Art of Summoning Objects in JavaScript](https://www.javascriptmancy.com/#get-the-books) a breathtaking story of EPIC proportions, awkward sense of humor and saving the world one JavaScript function at a time.*

```
JavaScript-mancy is a dangerous art.
Get an incantation slightly wrong,
and anything can happen. 

More than one young apprentice
has found out about this the hard way,
just a split second before 
razing a village to the ground,
letting loose a bloodthirsty beast,
or making something unexpected explode.

That's generally the way it is.

There are records of an ancient order,
an order of disciplined warrior monks,
who were able to tame the wild winds of magic.
But too little of them remains.

Did they exist? 
Or are they just wishful thinking and myth?
  
        - The Chronicler
```

> ```javascript
> /* 
> The group walks into the chamber and 
> the door closes itself behind them...
> 
> ...the chamber is poorly lit. A metal brazier of eerie blue 
> flames lies in the middle of the room and bathes a strange 
> obsidian obelisk in a mysterious light. Huge columns 
> surround the obelisk at irregular intervals. 
> Under the dim light it is impossible to ascertain 
> the room proportions...
> */
>
> mooleen.says('Something about this feels very wrong...');
> red.says("I couldn't agree more");
> 
> randalf.says("Well, it's either destroy that totem and " + 
>   "escape aided by magic or go back and fight The Red Legion" +
>   "with our bare fists");
> rat.says("...and sharp claws");
> 
> mooleen.says("Alright, let's get this over with");
>
> /* 
>   The group approaches the obelisk under an oppressive
>   silence only broken by the sound of boots scraping 
>   the sand covered ground.
> */
>
> red.says('Oh shit');
> mooleen.says('Oh shit? I thought you ' +
>   'were beyond that type of language');
> 
> /* 
>   Eerie blue and green lights start flaring around the
>   group inundating the chamber with light and a ghastly 
>   atmosphere. Up and up they go to reveal enormous terraces 
>   filled with dark winged figures. A voice suddenly booms 
>   within the chamber:
> */
> 
> voice.thunders('Let the games begin!');
> voice.thunders("In our next game we'll recreate " + 
>   "The Fall of the Order of The Red Moon " + 
>   "the sacred order of warrior monks" + 
>   "whose fierceness still echoes across the centuries");
> voice.thunders('I give you: The Last Stand!');
> 
> /* 
> A thunderous applause mixed with screeches, screams and 
> shouts of joy and excitement follows the proclamation.
> At the same time 4 humongous iron doors start slowly
> opening and row after row of obscene four-legged reptilian 
> creatures start emerging from them. Their impossibly huge 
> mandibles and terrible wails freeze your blood.
> */
>
> mooleen.says('Oh shit');
> 
> voice.thunders('The rules of the game:');
> voice.thunders('#1. Fight or Die...');
> voice.thunders('#2. You Shall Only Use Types!');
> voice.thunders('#3. Only One Shall Remain');
> ```

 
## You Shall Only Use Types!

Congratulations on making it to the end of the book! I have a special treat prepared for you as a farewell present: **TypeScript**! TypeScript has been gaining momentum over the past few years and it is used inside and outside of the .NET world even with popular front-end frameworks such as Angular and React. TypeScript provides the nearest experience to C# that you can find on the web. Enjoy!

## JavaScript + Types = Awesome Dev Productivity

TypeScript is a superset of JavaScript that adds type annotations and, thus, static typing on top of JavaScript. 

If you are a C# or Java developer you'll feel right at home writing TypeScript. If you are a JavaScript developer or have a background in dynamic programming languages you'll encounter a slightly more verbose version of JavaScript that results in a safer and better developer experience. Either way, you'll be happy to know that everything you've learned about JavaScript thus far also applies to TypeScript, that is, **any JavaScript is valid TypeScript**.

## Any JavaScript is Valid TypeScript

> ### Experiment JavaScriptmancer!!
>
> You can [experiment with the examples in this section using the TypeScript playground](https://bit.ly/javascriptmancy-oop-typescript-basic) or downloading the source code from [GitHub](https://github.com/vintharas/javascriptmancy).
>

Any bit of JavaScript is valid TypeScript. Let's say that we have the most basic piece of JavaScript code that you can write, a simple variable declaration that represents your reserve of mana:

```javascript
var manaReserves = 10;
```

And now let's say that we want to recharge your mana reserves by drinking a magic potion:

```javascript
function rechargeMana(potion){
  return potion.manaModifier * (Math.floor(Math.rand()*10) + 1);
}
```

So we go and write the following:

```javascript
manaReserves += rechargeMana({
  name: 'light potion of mana',
  manaModifier: 1.5 
});
```

When we execute the piece of code above, it explodes with the following error:

```javascript
// => Uncaught TypeError: Math.rand is not a function
```

Which makes sense because there's no such thing as a `Math.rand` function in JavaScript. It is called `Math.random`. For some reason I mix this function with a C function that has the same purpose, a slightly different name, and which I used in my student days. Regardless, I make this mistake, again and again.

The code above is a very traditional piece of JavaScript. But it is also completely valid TypeScript, with one difference. Writing the `rechargeMana` in TypeScript would have automatically resulted in a compiler error that would've read:

```javascript
Property 'rand' does not exist on type 'Math'.
```

This would have immediately alerted me to the fact that I'm making a mistake (again), and I would have been able to fix it before executing the program. This is one of the advantages of TypeScript: **shorter feedback loops where you can detect errors in your code at compile time instead of at runtime**.

Let's expand our previous example and drink another potion:

```javascript
rechagreMana({
  name: 'Greater Potion of Mana',
  manaModifier: 2
})
```

Again. A simple typo, a classic mistake in JavaScript that would result in a `ReferenceError` at runtime, is instantly caught by the TypeScript compiler:

```javascript
Cannot find name 'rechagreMana'.
```

As we've seen thus far, the TypeScript compiler that sits between the TypeScript code that you write and the output that runs in the browser can do a lot of things for you on vanilla JavaScript. But **it truly shines when you start adding type annotations**, that is, when you annotate your JavaScript code with additional bits of information regarding the type of things.

For instance, let's update our original `rechargeMana` function with some type annotations:

```typescript
function rechargeMana(potion: { manaModifier : number }) {
  return potion.manaModifier * (Math.floor(Math.random()*10) + 1);
}
```

The example above contains a type annotation for the `potion` parameter `{manaModifier : number} `. This annotation means that the `potion` parameter is expected to be an object that has a property `manaModifier` of type `number`. 

The type annotation does several things for us: 

1. It can help the compiler discover errors when the object passed as an argument to `rechargeMana` doesn't have the expected interface. That is, when it lacks the `manaModifier` property which is necessary for the function to work.
2. It can help the compiler discover typos or type errors when you use the `potion` object within the body of the function.
3. It gives us statement completion when typing `potion` inside the `rechargeMana` function which is a great developer experience[^statementcompletion]. If you aren't familiar with statement completion it consist on helpful in-editor information that pops up and tells you how you can use an object, like which properties are methods are available, which types are expected for the different parameters, etc.

[^statementcompletion]: The editor that you use should have a good integration with the TypeScript compiler to provide this type of service. Many of the most common IDEs and text editors have that support.

Let's illustrate 1) with an example. Imagine that in addition to potions of Mana you had potions of Strength:

```javascript
const potionOfStrength = {
  name: 'Potion of Strength',
  strengthModifier: 3,
  duration: 10
};
```

At some point in our program we could end up calling this code by mistake:

```javascript
rechargeMana(potionOfStrength);
```

Calling the `rechargeMana` function with a `potionOfStrength` as argument would result in a runtime error in JavaScript or, perhaps even in an elusive bug since multiplying `undefined` by a `number` results in `NaN` instead of crashing outright.

In TypeScript however, the example above would result in the following compiler error:

```typescript
// [ts] 
// Argument of type '{ name: string; strengthModifier: number; }' 
// is not assignable to parameter 
//   of type '{ manaModifier: number; }'.
// Property 'manaModifier' is missing 
// in type '{ name: string; strengthModifier: number; }'.
```

This error would quickly tell me that the potion of strength lacks the required contract to use `rechargeMana` and lots of tears and frustration would've been saved right then and there. Also take a second to appreciate the quality and precision of the error message above.

So any JavaScript is valid TypeScript. Change your `code.js` file into `code.ts` file, run it by the TypeScript compiler and TypeScript will try to infer the most information it can from your code and do its best to help you. Add type annotations on top of that and TypeScript will be able to learn more about your code and intentions, and provide you with better support.

## So, What Are The Advantages and Disadvantages of TypeScript?

By enhancing your JavaScript with new features, type annotations and static typing TypeScript provides these advantages:

* **Better error detection**. TypeScript can do static analysis of your code and reveal errors before running the actual code. This provides a much shorter feedback loop so that you can fix these errors as soon as they happen inside your editor and not after they hit production.
* **Better tooling and developer productivity**. The rich type information can be used by editors and IDEs to provide great tooling to enhance your developer productivity like in-editor compiler warnings, statement completion, safe refactorings, inline documentation, etc... [Visual Studio Code](https://code.visualstudio.com/) is a text editor that has awesome TypeScript support out of the box.
* **Great API discoverability**. Using statement completion provided by type annotations is an outstanding way to discover about new APIs right inside your editor.
* **Write more intentional code**. TypeScript type annotations and additional features like access level keywords allow you to constrain how the APIs that you design are meant to be used. This allows you to write more intentional code.
* **ESnext features**. TypeScript supports a lot of ESnext features like class members, decorators and `async/await`.
* **Additional TypeScript Features**. In addition to JavaScript and ESnext features TypeScript has a small number of features that are not in the ECMA-262 specification which add a lot to the language like property access levels and parameter properties.
* **Works with third-party libraries**. Using type annotations in your application code is awesome but what about all the third-party libraries that you use and are reference throughout your application code? How does TypeScript interact with them? Particularly, what happens when these libraries aren't written in TypeScript? In the worst case scenario TypeScript treats objects it doesn't know as of type `any` which basically means *"this object can have any shape so just behave as you would in JavaScript and don't make any assumptions"*. More often, third-party libraries either come with declaration files that provide typing information for TypeScript or you can find these declaration files through the [DefinitelyTyped project](http://definitelytyped.org/) a repository of TypeScript type definitions. This means that you'll be able to enjoy the same level of TypeScript support (or even greater) for third-party libraries that you do for your own code.
* **Great for large-scale applications and teams**. TypeScript excels at supporting multiple teams with large-scale applications. The type annotations and the TypeScript compiler are awesome at catching breaking changes, subtle bugs and with new APIs discoverability.

On the minus side:

* **TypeScript requires a transpilation step**. TypeScript code is not supported as-is in any browser. In order to be able to write your applications in TypeScript you need to setup some sort of build pipeline to transpile your TypeScript code into a version of JavaScript that can run in the browser. Fortunately, there is great support for this in the open source community and you can find great integrations for TypeScript in the most popular frameworks and build tools.
* **You need to learn type annotations syntax and related artifacts**. The type annotations, their syntax and related artifacts like interfaces, generics, etc... add more cognitive load and an extra degree of complexity on top of all you need to know to write JavaScript applications.
* **It is verbose**. The addition of type annotations makes your JavaScript code more verbose (`call(person:Person)`) which can be quite aesthetically unpleasing (particularly at first). The TypeScript compiler does a great job at inferring types and reducing the amount of type annotations you need to write to the minimum but to make the most out of TypeScript you'll need to add a fair amount of type annotations yourself.
* **It sometimes falls out of line with the ECMAScript standard**. Bringing ESnext features to you today, although awesome, can have its drawbacks. Implementing ESnext features before they've been formalized can lead to TypeScript breaking with the standards as it happened with modules. Fortunately, the core philosophy of TypeScript being a superset of JavaScript led the TypeScript team to implement support for ES6 modules and to deprecate the non-standard version. This is a great indicator of TypeScript's allegiance to JavaScript but still bears consideration when adopting ESnext features. 

## Setting up a Simple TypeScript project

The best way to get an idea of the full-blown TypeScript development experience is to setup a simple TypeScript project from scratch and follow along for the rest of the chapter. As usual, you can download the source code for these and all examples from [GitHub](https://github.com/vintharas/javascriptmancy-code-samples).

The easiest way to get started is to install [node and npm](https://nodejs.org/en/) in your development computer. Once you've done that, we'll install the TypeScript compiler using npm:

```bash
$ npm install -g typescript
```

You can verify that the installation has worked correctly by running:

```bash
$ tsc -v
Version 2.4.2
```

And accessing the TypeScript compiler help:

```bash
$ tsc -h
Version 2.4.2
Syntax:   tsc [options] [file ...]

Examples: tsc hello.ts
          tsc --outFile file.js file.ts
          tsc @args.txt
```

I will use [Visual Studio Code](https://code.visualstudio.com/) during these examples but you're welcome to use [any editor that you prefer](http://www.typescriptlang.org/index.html#download-links). 

Typing this command below will create a new TypeScript file called `hello-wizard.ts` and will open it on Visual Studio Code: 

```bash
$ code hello-wizard.ts
```

Let's write the canonical hello wizard in TypeScript with a `sayHello` function:

```typescript
function sayHello(who: string) : void {
  console.log(`Hello ${who}! I salute you JavaScript-mancer!`);
}
```

Notice how we have added a type annotation `string` to the `who` parameter of this function. If we try to call the function with an argument that doesn't match the expected type of `string` the compiler will alert us with a compiler error inside our editor:

```typescript
sayHello(42);
// => [ts] Argument of type '42' is not assignable 
//         to parameter of type 'string'.
```

Let's fix it by saluting yourself. Update the code above to include your name inside a string:

```typescript
sayHello('<Your name here>');
```

Now you can compile the TypeScript file using the compiler within the terminal (Visual Studio comes with an embedded terminal that you can run inside the editor which is very convenient). Type:

```bash
$ tsc hello-world.ts
```

This will tell the TypeScript compiler to transpile your TypeScript application into JavaScript that can run in the browser. It will result in a vanilla JavaScript file `hello-world.js` that contains the following code:

```javascript
function sayHello(who) {
  console.log("Hello " + who + "! I salute you JavaScript-mancer!");
}
sayHello('<Your name here>');
```

Beautiful vanilla JavaScript as if you had typed it with your bare hands. You can use `node` to run this file:

```bash
$ node hello-world.js
Hello <Your name here>! I salute you JavaScript-mancer!
```

And TaDa! You've written, transpiled and run your first TypeScript program! World here we come! 

Since it can be slightly tedious to run the TypeScript compiler every time you make changes in your `ts` files, you can setup the compiler in **watch mode**. This will tell the TypeScript compiler to monitor your source code files and transpile them whenever it detects changes. To setup the TypeScript compiler in watch mode just type the following:

```bash
$ tsc -w hello-world.ts
10:55:11 AM - Compilation complete. Watching for file changes.
```

In the upcoming sections we will discover some of the great features you can use within TypeScript, all you need to know about TypeScript type annotations and what you need to think about when using TypeScript in real-world projects.

> ### Visual Studio Code Works Great With TypeScript!
>
> If you want to learn more about how to have a great setup in Visual Studio Code with TypeScript I recommend you to take a look at [this guide](https://bit.ly/vscode-ts).

## Cool TypeScript Features

In addition to type annotations, TypeScript improves JavaScript on its own right with ESnext features and some features of its own. 

> ### TypeScript brings you a lot of ESnext features
>
> A lot of the features that we'll see in this section are ESnext features that are proposals at different levels of maturity. You can find more information about all proposals currently under consideration in the [TC39 ECMA-262 GitHub repository](http://bit.ly/ecma262-gh). 
>
> Some of these features are available also when using Babel with experimental flags. The fact that you have a team within Microsoft maintaining TypeScript gives you a lot of confidence when using these features within TypeScript.

### TypeScript Classes

TypeScript classes come with several features that provide a much better developer experience than ES6 classes. The first one is **class members**. 

Instead of writing your classes like this:

```javascript
// ES6 class
class Gladiator {
  constructor(name, hitPoints){
    this.name = name;
    this.hitPoints = hitPoints;
  }
  toString(){
    return `${this.name} the gladiator`
  }
}
```

You can extract the class members `name` and `hitPoints` to the body of the class much like in statically typed languages:

```typescript
class Gladiator {
  name: string;
  hitPoints: number;

  constructor(name: string, hitPoints: number){
    this.name = name;
    this.hitPoints = hitPoints;
  }

  toString(){
    return `${this.name} the gladiator`
  }
}
```

This can be slightly verbose so TypeScript comes with another feature called **parameter properties** that allows you to specify a class member and initialize it via the constructor all in one go. 

An equivalent version to the one above using *parameter properties* would look like this:

```typescript
class SleekGladiator {
  constructor(public name: string, 
              public hitPoints: number){}

  toString(){
    return `${this.name} the gladiator`
  }
}
```

Better, isn't it? The `public` keyword within the class constructor tells TypeScript that `name` and `hitPoints` are class members that can be initialized via the constructor.

Moreover, the `public` keyword gives us a hint as to the last improvement that TypeScript brings to classes: **access modifiers**. TypeScript comes with four access modifiers that determine how you can access a class member: 

* **readonly**: Makes a member read only. You must initialize it upon declaration or within a constructor and it can't be changed after that.
* **private**: Makes a member private. It can only be accessed from within the class itself.
* **protected**: Makes a member protected. It can only be accessed from within teh class or derived types.
* **public**: Makes a member public. It can be accessed by anyone. Following JavaScript ES6 class implementation, `public` is the default access modifier for class members and methods if none is provided.

The `readonly` modifier saves us the necessity to define a `@readonly` decorator like we did in previous chapters. 

One shouldn't be able to change one's name once it's been given so let's make the `Gladiator` name read-only:

```typescript
class FixedGladiator {

  constructor(readonly name: string,
              public hitPoints: number){}

  toString(){
    return `${this.name}, the gladiator`
  }

}
```

Now when we create a new gladiator and we give him or her a name it'll be written in stone:

```typescript
const maximo = new FixedGladiator('Maximo', 5000);

maximo.name = "Aurelia";
// => [ts] Cannot assign to 'name' because it is 
//         a constant or a read-only property.
```

An important thing to note here is that these access modifiers are only applicable in the world of TypeScript. That is, the TypeScript compiler will enforce them when you are writing TypeScript but they'll be removed when your code is transpiled to JavaScript. 

The transpiled version of the `FixedGladiator` above results in the following JavaScript:

```javascript
var FixedGladiator = (function () {

  function FixedGladiator(name, hitPoints) {
    this.name = name;
    this.hitPoints = hitPoints;
  }

  FixedGladiator.prototype.toString = function () {
    return this.name + ", the gladiator";
  };

  return FixedGladiator;
}());
```

As you can appreciate from the example above there's no mechanism which ensures that the `name` property is read-only.

Next let's test the `private` access modifiers. In previous chapters we discussed different approaches that you can follow to achieve privacy in JavaScript: closures and symbols. With TypeScript you can achieve data hiding by using the `private` (and `protected`) access modifiers.

This was the example we used in *chapter 6. White Tower Summoning Enhanced: The Marvels of ES6 Classes* to showcase data hiding using closures:

```javascript
class PrivateBarbarian {

  constructor(name){
    // private members
    let weapons = [];
    // public members
    this.name = name;
    this["character class"] = "barbarian";
    this.hp = 200;

    this.equipsWeapon = function (weapon){ 
      weapon.equipped = true;
      // the equipsWeapon method encloses the weapons variable
      weapons.push(weapon);
      console.log(`${this.name} grabs a ${weapon.name} ` + 
                  `from the cavern floor`);
    };
    this.toString = function(){
      if (weapons.length > 0) {
        return `${this.name} wields a ` + 
               `${weapons.find(w => w.equipped).name}`;
      } else return this.name
    };
  }

  talks(){ 
    console.log("I am " + this.name + " !!!");
  }

  saysHi(){ 
    console.log("Hi! I am " + this.name);
  }
};
```

In this example we use closures to enclose the `weapons` variable which becomes private for all effects and purposes. As you can appreciate, the use of closures forces us to move the methods `equipsWeapon` and `toString` that make use of the `weapons` variable from the body of the class to the body of the constructor function.

The equivalent of this class in TypeScript looks like this:

```typescript
class PrivateBarbarian {
  // private members
  private weapons = [];

  // public members
  ["character class"] = "barbarian";
  hp = 200;

  constructor(public name: string) {}

  equipsWeapon(weapon) { 
    weapon.equipped = true;
    // the equipsWeapon method encloses the weapons variable
    this.weapons.push(weapon);
    console.log(`${this.name} grabs a ${weapon.name} ` + 
                `from the cavern floor`);
  }

  toString() {
    if (this.weapons.length > 0) {
    return `${this.name} wields a ` + 
            `${this.weapons.find(w => w.equipped).name}`;
    } else return this.name
  };

  talks(){ 
    console.log("I am " + this.name + " !!!");
  }

  saysHi(){ 
    console.log("Hi! I am " + this.name);
  }
};
```

If you now instantiate an indomitable barbarian and try to access the `weapons` property you'll be greeted by the following error:

```typescript
const conan = new PrivateBarbarian("shy Conan");
// const privateWeapons = conan.weapons;
// => [ts] Property 'weapons' is private and 
//         only accessible within class 'PrivateBarbarian'.
```

If you look back and compare both approaches I think that you'll agree with me that the TypeScript syntax reads better than the ES6 counterpart. Having all methods within the body of the class is more consistent and easier to understand than having methods split in two separate places.

On the flip side, the TypeScript `private` access modifier is a TypeScript feature that disappears when the code is transpiled to JavaScript, that is, a library consumer that had access to the output JavaScript would be able to access the `weapons` property of this class. This won't normally be a problem since most likely your whole development team will be working with TypeScript but there can be some cases where it could be problematic. For instance, I can see it being an issue for library creators that create their library using TypeScript and make it accessible to consumers that are using vanilla JavaScript.

#### Why Do I Get A TypeScript Error When Writing An ES6 class? Isn't It Valid JavaScript?

Excellent question! When you type the code example with the ES6 `Barbarian` class in your TypeScript editor of choice you'll be surprised to find that the `this.name`, `this.hp` and `this.equipsWeapon` declarations result in a TypeScript compiler error. *What?* I thought that every piece of JavaScript was valid TypeScript and this is perfectly valid ES6 code. *What's happening? Have I been living a lie?*

The reasons for these errors is that TypeScript has different levels of correctness:

* In the first level the TypeScript compiler examines whether the code is syntactically correct before applying type annotations. If it is, then it is capable of performing the transpilation and emitting correct JavaScript code (this is the case for the issue we've just discovered regarding ES6 classes). 
* In the second level the TypeScript compiler takes a look at the type annotations. According to TypeScript's type system, the `PrivateBarbarian` doesn't have any property `name` (properties are declared within the body of a class) and therefore it shows the error *[ts] Property 'name' does not exist on type 'PrivateBarbarian'*.
* In the third level enabled via the compiler flag `--noImplicitAny` the TypeScript compiler will become very strict and won't assume that the type of a non annotated variable is `any`. That is, it will require that all variables, properties and methods be typed.

So in our ES6 example, TypeScript understands your code as valid ES6 and will be able to transpile your code into JavaScript but according to TypeScript's type system you should refactor your class and move the class members inside the class body.

### Enums

Another great feature in TypeScript are enums. Enums are a common data type in statically typed languages like C# and Java that are used to represent a finite number of things in an strongly typed fashion.

Imagine that you want to express all the different Schools of Elemental Magic: Fire, Water, Air and Earth. When you create diverse elemental spells, these will belong to some of several of these schools and will have advantages and disadvantages against spells of other schools. For instance, a fireball spell could look like this:

```javascript
const fireballSpell = {
  type: 'fire',
  damage: 30,
  cast(target){
    const actualDamage = target.inflictDamage(this.damage, 
                                              this.type);
    console.log(`A huge fireball springs from your ` +  
        `fingers and impacts ${target} (-${actualDamage}hp)`);
  }
};
```

The `target.inflictDamage` would calculate the `actualDamage` inflicted on a target by taking into account the target resistance to a specific elemental magic or whether it has protective spells against it.

The problem with this example is that strings aren't very intentional nor provide a lot of information about the Schools of Elemental Magic that are available. In the example above it'd be very easy to have a typo and misspell the string `'fire'` for something else. 

An improvement over the previous approach is to use an object to encapsulate all available options:

```javascript
const schoolsOfElementalMagic = {
  fire: 'fire',
  water: 'water',
  air: 'air',
  earth: 'earth'
};
```

And now we can rewrite our previous example:

```javascript
const fireballSpell = {
  type: schoolsOfElementalMagic.fire,
  damage: 30,
  cast(target){
    const actualDamage = target.inflictDamage(this.damage, 
                                              this.type);
    console.log(`A huge fireball springs from your ` +  
        `fingers and impacts ${target} (-${actualDamage}hp)`);
  }
};
```

Awesome! That's much better than the magic string we had earlier. But it's still susceptible to typos and there's nothing stopping you from writing `type: 'banana'` inside your spell. 

That's where TypeScript enums come in. They give you a statically and strongly typed way to represent a limited collection of things or states. A `SchoolsOfMagic` enum could look like this:

```typescript
enum SchoolsOfMagic {
  Fire,
  Water,
  Air,
  Earth
}
```

This enum allows us to specify an interface that represents the shape of a `Spell`. Note how a valid `Spell` has a `type` property whose type is the enumeration `SchoolsOfMagic` we just created:

```typescript
// now we can define a Spell interface
interface Spell {
  type: SchoolsOfMagic,
  damage: number,
  cast(target: any);
}
```

> ### Interfaces?
>
> Interfaces are another new feature in TypeScript. They allow you to define arbitrary types that result in more intentional code and enrich your developer experience. We'll learn more about interfaces later in this chapter.

When we now define a new spell TypeScript will enforce that the `type` provided for the spell is of type `SchoolsOfMagic`, and not only that, when using an editor such as Visual Studio Code it will give us all the available options (`Fire`, `Water`, `Air` and `Earth`) via statement completion.

```typescript
const enumifiedFireballSpell: Spell = {
  type: SchoolsOfMagic.Fire,
  damage: 30,
  cast(target){
    const actualDamage = target.inflictDamage(this.damage, 
                                              this.type);
    console.log(`A huge fireball springs from your ` +  
        `fingers and impacts ${target} (-${actualDamage}hp)`);
  }
}
```

If we were to type anything else than the `SchoolOfMagic` enum (for instance, a string) TypeScript would warn us instantly with the following error message:

```typescript
// providing other than a SchoolsOfMagic enum would result in error:
// [ts] 
//   Type 
//  '{ type: string; damage: number; cast(target: any): void; }' 
//   is not assignable to type 'Spell'.
//   Types of property 'type' are incompatible.
//   Type 'string' is not assignable to type 'SchoolsOfMagic'.
```

When transpiled to JavaScript enums result in the following code:
 
```javascript
var SchoolsOfMagic;
(function (SchoolsOfMagic) {
    SchoolsOfMagic[SchoolsOfMagic["Fire"] = 0] = "Fire";
    SchoolsOfMagic[SchoolsOfMagic["Water"] = 1] = "Water";
    SchoolsOfMagic[SchoolsOfMagic["Air"] = 2] = "Air";
    SchoolsOfMagic[SchoolsOfMagic["Earth"] = 3] = "Earth";
})(SchoolsOfMagic || (SchoolsOfMagic = {}));
```

At first sight it may look a little bit daunting. But let's decompose it into smaller statements:

```javascript
// Set 'Fire' property in SchoolsOfMagic to 0
SchoolsOfMagic["Fire"] = 0;

// it evaluates to 0 so that this:
SchoolsOfMagic[SchoolsOfMagic["Fire"] = 0] = "Fire";
// is equivalent to:
SchoolsOfMagic[0] = "Fire";
// which means set '0' property in SchoolsOfMagic to "Fire"
```

So an enum represents a two-way mapping between numbers and strings with the enum name. Just like you can specify the names, you can select the numbers when declaring the enum:

```typescript
// Start in 1 and increase numbers
enum SchoolsOfMagic {
  Fire=1,
  Water,
  Air,
  Earth
}

// Explicitly set all numbers
enum SchoolsOfMagic {
  Fire=2,
  Water=4,
  Air=6,
  Earth=8
}

// Computed enums
enum SchoolsOfMagic {
  Fire=1,
  Water=Fire*2,
  Air=2,
  Earth=Air*2
}
```

Whenever we don't want for the transpiled JavaScript to contain reference to enums (for instance, in a constrained environment were we want to ship less code) we can use `const` enums. The following enum definition will not be transpiled to JavaScript: 

```typescript
const enum SchoolOfMagic {
  Fire,
  Water,
  Air,
  Earth
}
``` 

Instead it will be inlined and any reference to `Fire`, `Water`, `Air` and `Earth` will be replaced by a number. In this case 0, 1, 2, 3 respectively.

### Still prefer strings? Check This String Literal Types

If you still prefer vanilla strings TypeScript has the ability to create types based on a series of specific valid strings. An equivalent for our schools of magic could look like this:

```typescript
type SchoolsOfMagic = "fire" | "earth" | "air" | "water";
```

Again we define an interface in terms of this new type:

```typescript
interface Spell {
  type: SchoolsOfMagic,
  damage: number,
  cast(target: any);
}
```

And we're ready to create spells. Using anything other than the allowed strings will result in a transpilation error:

```typescript
const FireballSpell: Spell = {
  type: "necromancy", 
  damage: 30,
  cast(target){
    const actualDamage = target.inflictDamage(this.damage, this.type);
    console.log(`A huge fireball springs from your ` +  
        `fingers and impacts ${target} (-${actualDamage}hp)`);
  }
}
// => [ts] 
//  Type '{ type: "necromancy"; damage: number; 
//          cast(target: any): void; }' 
//  is not assignable to type 'SpellII'.
//  Types of property 'type' are incompatible.
//  Type '"necromancy"' is not assignable to type 'SchoolsOfMagicII'.
```

### Object Spread and Rest

In **JavaScript-mancy: Getting Started** we saw **rest parameters** and **the spread operator** brought by ES6. 

As you can probably remember, *rest parameters* improve the developer experience of declaring functions with multiple arguments [^multiple]. Instead of using the `arguments` object like we used to do prior to ES6:

[^multiple]: Like `params` in C#.

```typescript
function obliterate(){
  // Unfortunately arguments is not an array :O
  // so we need to convert it ourselves
  var victims = Array.prototype.slice.call(arguments, 
                              /* startFromIndex */ 0);

  victims.forEach(function(victim){
    console.log(victim + " wiped off of the face of the earth");
  });
  console.log('*Everything* has been obliterated, ' + 
              'oh great master of evil and deceit!');
}
```

We can use rest syntax to collect all incoming arguments directly into an array `victims`:

```typescript
function obliterate(...victims){
  victims.forEach(function(victim){
    console.log(`${victim} wiped out of the face of the earth`);
  });
  console.log('*Everything* has been obliterated, ' + 
              'oh great master of evil and deceit!');
}
```

On the other hand the *spread operator* works sort of in an opposite way to *rest parameters*. Instead of taking a variable number of arguments and packing them into an array, the spread operator takes an array and expands it into its compounding items.

Following this principle the spread operator has many use cases[^use-cases]. Like concatenating arrays:

[^use-cases]: Go back and review JavaScript-mancy: Getting Started for lots more of use cases! 

```javascript
let knownFoesLevel1 = ['rat', 'rabbit']
let newFoes = ['globin', 'ghoul'];
let knownFoesLevel2 = [...knownFoesLevel1, ...newFoes];
```

Or cloning them:

```javascript
let foes = ['globin', 'ghoul'];
let clonedFoes = [...foes];
```

**Object Spread and Rest** brings this same type of functionality that is available in arrays to objects. 

A great use case for the **Object spread operator** are mixins. In previous chapters we used `Object.assign` to mix the properties of two or more different objects. For instance, in this `Wizard` factory function we mix the wizard properties with mixins that encapsulate behaviors to identify something by name and cast spells:

```javascript
function Wizard(element, mana, name, hp){
  let wizard = {element, 
                mana, 
                name, 
                hp};
  Object.assign(wizard, 
               canBeIdentifiedByName,
               canCastSpells);
  return wizard;
}
```

We can rewrite the example above using object spread as follows:

```typescript
function Wizard(element, mana, name, hp){
  let wizard = {element, 
                mana, 
                name, 
                hp};

  // now we use object spread
  return {...wizard, 
          ...canBeIdentifiedByName,
          ...canCastSpells
         };
}
```

The object spread operator essentially says: *get all properties of `wizard`, `canBeIdentifiedByName` and `canCastSpells` and put them together within the same object*. If there are any properties that have the same name, the last one wins and overwrites the first.

The opposite to object spread are object rest parameters. They work in a similar fashion to ES6 rest parameters and are particularly helpful together with ES6 destructuring. 

If you remember, we used destructuring and rest parameters to extract elements from an array:

```javascript
let [first, second, ...rest] = ['dragon', 'chimera', 'harpy', 'medusa'];
console.log(first); // => dragon
console.log(second); // => chimera
console.log(rest); // => ['harpy', 'medusa']
```

With the Object Spread Operator we can follow the same pattern to extract and collect properties from objects:

```typescript
let {name, type, ...stats} = {
  name: 'Hammer of the Morning',
  type: 'two-handed war hammer',
  weight: '40 pounds',
  material: 'nephirium',
  state: 'well kept'
};
console.log(name); // => Hammer of Morning
console.log(type); // => two-handed war hammer
console.log(stats); 
// => {weight: '40 pounds', 
//     material: 'nephirium', 
//     state: 'well kept'}
```

### And There's More!

There's a lot more features in TypeScript that expand on ES6 either via early implementation of ESnext features that are currently in a proposal stage (like `async/await` or decorators ) or via entirely new features like the ones we've seen related to classes and enums. 

If you're interested into learning more about TypeScript then I encourage you to take a look at the [TypeScript handbook](http://bit.ly/ts-handbook) and at the [release notes](http://bit.ly/ts-whats-new) both of which provide detailed information about what TypeScript has in store for you.

## Type Annotations In TypeScript

Type annotations are TypeScript's bread and butter and provide yet a new level of meta-programming in JavaScript: type meta-programming. Type annotations give you the ability to create a better developer experience for you and your team by ways of shorter feedback loops, compile time errors and API discoverability.

Type annotations in TypeScript don't stop at simple primitive types like `string` or `number`. You can specify the type of arrays:

```typescript
// An array of strings
let saddleBag: string[] = [];
saddleBag.push('20 silvers');
saddleBag.push('pair of socks');

saddleBag.push(666);
// => [ts] Argument of type '666' is not assignable 
//         to parameter of type 'string'.
```

and tuples:

```typescript
// A tuple of numbers
let position : [number, number];
position = [1, 1];
position = [2, 2];

// position = ['orange', 'delight'];
// => [ts] Type '[string, string]' is not 
//    assignable to type '[number, number]'.
//    Type 'string' is not assignable to type 'number'.
```

functions:

```typescript
// a predicate function that takes numbers and returns a boolean
let predicate: (...args: number[]) => boolean;
predicate = (a, b) => a > b
console.log(`1 greated than 2? ${predicate(1, 2)}`);
// => 1 greated than 2? false

predicate = (text:string) => text.toUpperCase();
// => [ts] Type '(text: string) => string' is not assignable 
//         to type '(...args: number[]) => boolean'.
//     Types of parameters 'text' and 'args' are incompatible.
//     Type 'number' is not assignable to type 'string'.
```

and even objects:

```typescript
function frost(minion: {hitPoints: number}) {
  const damage = 10;
  console.log(`${minion} is covered in frozy icicles (- ${damage} hp)`);
  minion.hitPoints -= damage;
}
```

The `{hitPoints: number}` represents and object that has a `hitPoints` property of type `number`. We can cast a frost spell on a dangerous foe that must comply with the required contract - that of having a `hitPoints` property:

```typescript
const duck = {
  toString(){ return 'a duck';}, 
  hitPoints: 100
};

frost(duck);
// => a duck is covered in frozy icicles (-10hp)
```

If the object frozen doesn't satisfy the requirements, TypeScript will alert us instantly:

```typescript
const theAir = {
    toString(){ return 'air';}
};
frost(theAir);
// => [ts] Argument of type '{ toString(): string; }' 
//    is not assignable to parameter 
//      of type '{ hitPoints: number; }'.
// Property 'hitPoints' is missing in type '{ toString(): string; }'.
```

An even better way to annotate objects is through **interfaces**.

### TypeScript Interfaces

Interfaces are reusable and less verbose than straight object type annotations. A `Minion` interface could be described as follows:

```typescript
interface Minion {
    hitPoints: number;
}
```

We could use this new interface to update our `frost` function:

```typescript
function frost(minion: Minion){
  const damage = 10;
  console.log(`${minion} is covered in frozy icicles (-${damage} hp)`);
  minion.hitPoints -= damage;
}
```

Looks nicer, doesn't it? An interesting fact about **interfaces** is that they are entirely a TypeScript artifact whose only application is within the realm of type annotations and the TypeScript compiler. Because of that, **interfaces** are not transpiled into JavaScript. If you transpile the code above you'll be surprised to see that the resulting JavaScript has no mention of `Minion`:

```javascript
function frost(minion) {
    var damage = 10;
    console.log(minion + " is covered in frozy icicles (-" + damage + " hp)");
    minion.hitPoints -= damage;
}
```

This points to the fact that interfaces are a lightweight approach to adding type annotations to your codebase, reaping the benefits during development without having any negative impact in the code that runs on the browser.

Let's test our new `frost` function and the `Minion` interface with different types of arguments and see how they behave. Bring on the `duck` from our previous example!

```typescript
// const duck = {
//  toString(){ return 'duck';}, 
//  hitPoints: 100
//  };
frosty(duck);
// => duck is covered in frozy icicles (-10hp)
```

That seems to work perfectly. If we try with a class that represents a `Tower` and has a `hitPoints` and a `defense` property it seems to work as well:

```typescript
class Tower {
    constructor(public hitPoints=500, public defense=100){}
    toString(){ return 'a mighty tower';}
}
const tower = new Tower();

frosty(tower);
// => a mighty tower is covered in frozy icicles (-10hp)
```

And so does a simple object literal with the `hitPoints` property:

```typescript
frosty({hitPoints: 100});
// => [object Object] is covered in frozy icicles (-10hp)
```

However if we use an object literal that has another property in addition to `hitPoints` the compiler throws an error:

```typescript
frosty({hitPoints: 120, toString(){ return 'a bat';}})
// => doesn't compile
// => Argument of type '{ hitPoints: number; toString(): string; }' 
//    is not assignable to parameter of type 'Minion'.
//  Object literal may only specify known properties, 
//  and 'toString' does not exist in type 'Minion'.
```

The error message seems to be very helpful. It says that with object literals I may only specify known properties and that `toString` doesn't exist in `Minion`. So what happens if I store the object literal in a variable `aBat`?

```typescript
let aBat = {
    hitPoints: 120, 
    toString(){ return 'a bat';}
};
frosty(aBat);
// => a bat is covered in frozy icicles (-10hp)
```

It works! Interesting, from these experiments it looks like TypeScript will consider a `Minion` to be any object that satisfies the contract specified by the interface, that is, to have a `hitPoints` property of type `number`. 

However, it looks like when you use an object literal TypeScript has a somewhat more strict set of rules and it expects an argument that exactly matches the `Minion` interface. So what is a `Minion` exactly? When TypeScript encounters an arbitrary object, how does it determine whether it is a `Minion` or not? 

**It follows the rules of structural typing**.

### Structural Typing

**Structural typing is a type system where type compatibility and equivalence are determined by the structure of the types being compared, that is, their properties**. 

For instance, following structural typing all of the types below are equivalent because they have the same structure (the same properties):

```typescript
// an interface
interface Wizard {
  hitPoints: number;
  toString(): string;
  castSpell(spell:any, targets: any[]);
}

// an object literal
const bard = {
  hitPoints: 120,
  toString() { return 'a bard';},
  castSpell(spell: any, ...targets: any[]){
    console.log(`${this} cast ${spell} on ${targets}`);
    spell.cast(targets);
  }
}

// a class
class MagicCreature {
  constructor(public hitPoints: number){}
  toString(){ return "magic creature";}
  castSpell(spell: any, ...targets: any[]){
    console.log(`${this} cast ${spell} on ${targets}`);
    spell.cast(targets);
  }
}
```

Which you can verify using this snippet of code:

```typescript
let wizard: Wizard = bard;
let anotherWizard: Wizard = new MagicCreature(120);
```

In contrast, languages like C# or Java have what we call a **nominal type system**. In nominal type systems, type equivalence is based on the names of types and explicit declarations, where a `MagicCreature` is a `Wizard`, if and only if, the class implements the interface explicitly.

Structural typing is awesome for JavaScript developers because it behaves very much like duck typing that is such a core feature to JavaScript object-oriented programming model. It is still great for C#/Java developers as well because they can enjoy C#/Java features like interfaces, classes and compile-time feedback but with a higher degree of freedom and flexibility.

There's still one use case that doesn't fit the structural typing rule we just described. If you remember the examples from the previous section, object literals seem to be an exception to the structural typing rule:

```typescript
frosty({hitPoints: 120, toString(){ return 'a bat';}})
// => doesn't compile
// => Argument of type '{ hitPoints: number; toString(): string; }' 
//    is not assignable to parameter of type 'Minion'.
//  Object literal may only specify known properties, 
//  and 'toString' does not exist in type 'Minion'.
```

Why does that happen? It happens in order to prevent developer mistakes. 

The TypeScript compiler designers considered that using object literals like this can be prone to errors and mistakes (like typos, imagine writing `hitPoitns` instead of `hitPoints`). That is why when using object literals in this fashion the TypeScript compiler will be extra diligent and perform **excess property checking**. Under this special mode TypeScript will be inclined to be extra careful and will flag any additional property that the function `frosty` doesn't expect. Everything in the hopes of helping you avoid unnecessary mistakes.

If you are sure that your code is correct, you can quickly tell the TypeScript compiler that there's no problem by explicitly casting the object literal to the desired type or storing it in a variable as we saw earlier:

```typescript
frosty({hitPoints: 120, toString(){ return 'a bat';}} as Minion);
// => a bat is covered in frozy icicles (-10hp)
```

Notice the `as Minion`? That's a way we can tell TypeScript that the object literal is of type `Minion`. This is another way:

```typescript
frosty((<Minion>{hitPoints: 120, toString(){ return 'a bat';}}));
// => a bat is covered in frozy icicles (-10hp)
```

### TypeScript Helps You With Type Annotations

Another interesting facet of TypeScript are its **type inference** capabilities. Writing type annotations not only results in more verbose code but it's also additional work that you need to do. In order to minimize the amount of work that you need to put in to annotate your code, TypeScript will do its best to infer the types used from the code itself. For instance:

```typescript
const aNumber = 1;
const anotherNumber = 2 * aNumber;

// aNumber: number
// anotherNumber:number
```

In this code sample we haven't specified any types. Regardless, TypeScript knows without the shadow of a doubt that the `aNumber` variable is of type `number`, and by evaluating `anotherNumber` it knows that it's also of type `number`. Likewise we can write the following:

```typescript
const double = (n: number) => 2*n;
// double: (n:number) => number
```

And TypeScript will know that the function `double` returns a number.

### From Interfaces to Classes

So far we've seen how you can use type annotations in the form of primitive types, arrays, object literals and interfaces. All of these are TypeScript specific artifacs that disappear when you transpile your TypeScript code to JavaScript. We've also seen how TypeScript attempts to infer types from your code so that you don't need to expend unnecessary time annotating your code.

Then we have classes. Classes are a ES6/TypeScript feature that we can use to describe a domain model entity in structure and behavior, which contain a specific implementation, and which also serve as a type annotation. 

In previous sections we defined an interface `Minion` that represented a thing with a `hitPoints` property. We can do the same with a class:

```typescript
class ClassyMinion {
  constructor(public hitPoints: number) {}
}
```

And create a new `classyFrost` function to use this class as the argument type:

```typescript
function classyFrost(minion: ClassyMinion){
  const damage = 10;
  console.log(`${minion} is covered in frozy icicles (-${damage} hp)`)
  minion.hitPoints -= damage;
}
```

We can use this function with our new `ClassyMinion` class and even with the previous `aBat` and `bard` variables because following the rules of structural typing all of these types are equivalent:

```typescript
classyFrosty(new ClassyMinion());
// => a classy minion is covered in frozy icicles (-10hp)
classyFrosty(aBat);
// => a bat is covered in frozy icicles (-10hp)
classyFrosty(bard);
// => a bard is covered in frozy icicles (-10hp)
```

Normally we would have the `class` implement the desired `interface`. For instance:

```typescript
class ClassyMinion implements Minion {
  constructor(public hitPoints: number) {}
}
```

This wouldn't make a change in how this class is seen from a structural typing point of view but it does improve our developer experience. Adding the `implements Minion` helps TypeScript tell us whether we have implemented an interface correctly or if we're missing any properties or methods. This may not sound like much in a class with one single property but it's increasingly helpful as our classes become more meaty.

In general, the difference between using a `class` and using an `interface` is that the class will result in a real JavaScript class when transpiled to JavaScript (although it could be a constructor/prototype pair depending on the JavaScript version your are targeting). 

For instance, the class above will result in the following JavaScript in our current setup:

```javascript
var ClassyMinion = (function () {
    function ClassyMinion(hitPoints) {
        if (hitPoints === void 0) { hitPoints = 100; }
        this.hitPoints = hitPoints;
    }
    ClassyMinion.prototype.toString = function () {
        return 'a classy minion';
    };
    return ClassyMinion;
}());
```

This makes sense because, unlike an `interface` which is a made up artifact used only in the world of TypeScript type annotations, a `class` is necessary to run your program.

**When do you use interfaces and when do you use classes then?** Let's review what both of these constructs do and how they behave:

* **Interface**: Describes shape and behavior. It's removed during transpilation process.
* **Class**: Describes shape and behavior. Provides a specific implementation. It's transpiled into JavaScript

So both interfaces and class describe the shape and behavior of a type. And additionally, classes provide a concrete implementation.

In the world of C# or Java, following the **dependency inversion** principle we'd advice to prefer using interfaces over classes when describing types. That would afford us a lot of flexibility and extensibility within our programs because we would achieve a loosely coupled system where concrete types don't know about each other. We then would be in a position to inject diverse concrete types that would fulfill the contract defined by the interfaces. This is a must in statically typed languages like C# or Java because they use a nominal type system. But what about TypeScript?

As we mentioned earlier, TypeScript uses a structural type system where types are equivalent when they have the same structure, that is, the same members. In light of that, you could say that it doesn't really matter if we use interfaces or classes to denote types. If interfaces, classes or object literals share the same structure, they'll be equally treated, so why would we need to use interfaces in TypeScript? Here are some guidelines that you can follow when you consider using interfaces vs classes:

1. The single responsibility is a great rule of thumb to decrease the complexity of your programs. **Applying the single responsibility to the interface vs class dilemma we can arrive to use interfaces for types and classes for implementations**. Interfaces provide a very concise way to represent the shape of a type, whilst classes intermingle both the shape and the implementation which can make it hard to ascertain what the shape of a type is by just looking at a class.
2. `interfaces` give you more flexibility than classes. Because a class contains a specific implementation, it is, by its very nature, more rigid than an interface. Using interfaces we can capture finely grained details or bits of behavior that are common between classes.
3. `interfaces` are a lightweight way to provide type information to data that may be foreign to your application like data coming from web services
4. For types with no behavior attached, types that are merely data, you can use a class directly. Using an interface in this case will often be overkill and unnecessary. Using a class will ease object creation via the constructor.

So, in general, the same guidelines that we follow regarding interfaces in statically typed languages like C# and Java also apply to TypeScript. Prefer to use interfaces to describe types and use classes for specific implementations. If the type is just data with no behavior you may consider using a class on its own.

### Advanced Type Annotations

In addition to what we've seeing thus far TypeScript provides more mechanisms to express more complex types in your programs. The idea is that, whichever JavaScript construct or pattern you use, you should be able to express its type via type annotations and provide helpful type information for you and other developers within your team. 

Some examples of these advanced type annotations are:

* Generics
* Intersection and Union Types
* Type Guards
* Nullable Types
* Type Aliases
* String-literal Types

Let's take a look at each of them, why they are needed and how to use them.

#### Generics

Generics is a common technique used in statically typed programming languages like C# and Java to generalize the application of a data structure or algorithm to more than one type. 

For instance, instead of having a separate `Array` implementation for each different type: `NumberArray`, `StringArray`, `ObjectArray`, etc:

```typescript
interface NumberArray {
  push(n: number);
  pop(): number;
  [index: number]: number;
  // etc
}

interface StringArray {
  push(s: string);
  pop(): string;
  [index: number]: string;
  // etc
}

// etc...
```

We use generics to describe an `Array` of an arbitrary type `T`:

```typescript
// note that `Array<T>` is already a built-in type in TypeScript
interface Array<T>{
  push(s: T);
  pop(): T;
  [index: number]: T;
  // etc
}
```

We can now reuse this single type definition by selecting a type for `T`:

```typescript
let numbers: Array<number>;
let characters: Array<string>;
// and so on...
```

And just like we used generics with interfaces, we can use them with classes:

```typescript
class Cell<T> {
  private prisoner: T;

  inprison(prisoner: T) { 
    this.prisoner = item; 
  }

  free(): T { 
    const prisoner = this.prisoner; 
    this.prisoner = undefined;
    return prisoner;
  }
}
```

Finally, you can constrain the type `T` to only a subset of types. For instance, let's say that a particular function only makes sense within the context of `Minion`. You can write:

```typescript
interface ConstrainedCell<T extends Minion>{
  inprison(prisoner: T);
  free(): T;
}
```

And now this will be a perfectly usable box:

```typescript
let box: ConstrainedCell<MagicCreature>;
```

But this won't because the type `T` doesn't match the `Minion` interface:

```typescript
let box: ConstrainedCell<{name: string}>;
// => [ts] Type '{ name: string; }' 
//    does not satisfy the constraint 'Minion'.
//    Property 'hitPoints' is missing in type '{ name: string; }'.
```

#### Intersection and Union Types

We've seen primitive types, interfaces, classes, generics, a lot of different ways to provide typing information but flexible as these may be, there's still a use case which they have a hard time covering: **Mixins**.

When using mixins the resulting object is a mix of other different objects. The type of this resulting object is not a known type in its own right but a combination of existing types. 

For instance, let's go back to the Wizard example that we had earlier:

```typescript
function Wizard(element, mana, name, hp){
  let wizard = {element, 
                mana, 
                name, 
                hp};

  // now we use object spread
  return {...wizard, 
          ...canBeIdentifiedByName,
          ...canCastSpells
         };
}
```

We can decompose this into separate elements:

```typescript
interface WizardProps{
  element: string;
  mana: number;
  name: string;
  hp: number;
}

interface NameMixin {
  toString(): string;
}

interface SpellMixin {
  castsSpell(spell:Spell, target: Minion);
}
```

How can we define the resulting `Wizard` type that is the combination of `WizardProps`, `NameMixin` and `SpellMixin`? We use **Intersection Types**. An Intersection Type allows us to define types that are the combination of other types. For instance, we could represent our `Wizard` using the following type annotation:

```typescript
WizardProps & NameMixin & SpellMixin
```

And we could use it as a return type of our factory function:

```typescript
let canBeIdentifiedByName: NameMixin = {
  toString(){ return this.name; }
};

let canCastSpells: SpellMixin = {
  castsSpell(spell:Spell, target:Minion){
    // cast spell
  }
}

function WizardIntersection(element: string, mana: number, 
                            name : string, hp: number): 
         WizardProps & NameMixin & SpellMixin {
  let wizard: WizardProps = {element, 
                mana, 
                name, 
                hp};

  // now we use object spread
  return {...wizard, 
          ...canBeIdentifiedByNameMixin,
          ...canCastSpellsMixin
         };
}

const merlin = WizardIntersection('spirit', 200, 'Merlin', 200);
// merlin.steal(conan);
// => [ts] Property 'steal' does not exist 
//    on type 'WizardProps & NameMixin & SpellMixin'.
```

In the same way that we have a Intersection Types that result in a type that is a combination of other types we also have the ability to make a type that can be any of a series of types, that is, either `string` or `number` or other type. We call these types **Union Types**. They are often used when you have overloaded functions or methods that may take a parameter with varying types.

Take a look at the following function that raises an skeleton army:

```javascript
function raiseSkeleton(numberOrCreature){
  if (typeof numberOrCreature === "number"){
    raiseSkeletonsInNumber(numberOrCreature);
  } else if (typeof numberOrCreature === "string") {
    raiseSkeletonCreature(numberOrCreature);
  } else {
    console.log('raise a skeleton');
  }

  function raiseSkeletonsInNumber(n){
    console.log('raise ' + n + ' skeletons');
  }
  function raiseSkeletonCreature(creature){
    console.log('raise a skeleton ' + creature);
  };
}
```

Depending on the type of `numberOrCreature` the function above can raise skeletons or skeletal creatures:

```javascript
raiseSkeleton(22);
// => raise 22 skeletons

raiseSkeleton('dragon');
// => raise a skeleton dragon
```

We can add some TypeScript goodness to the `raiseSkeletonTS` function using union types:

```typescript
function raiseSkeletonTS(numberOrCreature: number | string){
  if (typeof numberOrCreature === "number"){
    raiseSkeletonsInNumber(numberOrCreature);
  } else if (typeof numberOrCreature === "string") {
    raiseSkeletonCreature(numberOrCreature);
  } else {
    console.log('raise a skeleton');
  }

  function raiseSkeletonsInNumber(n: number){
    console.log('raise ' + n + ' skeletons');
  }
  function raiseSkeletonCreature(creature: string){
    console.log('raise a skeleton ' + creature);
  };
}
```

The `number | string` is a Union Type that allows `numberOrCreature` to be of type `number` or `string`. If we by mistake use something else, TypeScript has our backs:

```typescript
raiseSkeletonTS(['kowabunga'])
// => [ts] Argument of type 'string[]' is not assignable 
//         to parameter of type 'string | number'.
// Type 'string[]' is not assignable to type 'number'.
```

#### Type Guards

Union types raise a special case inside the body of a function. If `numberOrCreature` can be a number or a string, how does TypeScript know which methods are supported? Number methods differ greatly from String methods, so what is allowed? 

When TypeScript encounters a union type as in the function above, by default, you'll only be allowed to use methods and properties that are available in all the types included. It is only when you do a explicit conversion or include a type guard that TypeScript will be able to determine the type in use and be able to assist you. Fortunately, TypeScript will recognize type guards that are common JavaScript patterns, like the `typeof` that we used in the previous example. After performing a type guard `if (typeof numberOrCreature === "number")` TypeScript will know with certainty that whatever piece of code you execute inside that if block the `numberOrCreature` will be of type `number`.

#### Type Aliases

Another helpful mechanism that works great with Intersection and Union Types are Type Aliases. Type Aliases allow you to provide arbitrary names (aliases) to refer to other types. Tired of writing this Intersection Type?

```typescript
WizardProps & NameMixin & SpellMixin
```

You can create an alias `Wizard` and use that instead:

```typescript
type Wizard = WizardProps & NameMixin & SpellMixin;
```

This alias will allow you to improve the *Wizard* factory from previous examples:

```typescript
function WizardAlias(element: string, mana: number, 
                name : string, hp: number): Wizard {
  let wizard: WizardProps = {element, 
                mana, 
                name, 
                hp};

  // now we use object spread
  return {...wizard, 
          ...canBeIdentifiedByNameMixin,
          ...canCastSpellsMixin
         };
}
```

#### More Type Annotations!

Although I've tried to be quite comprehensive in covering TypeScript within this final chapter of the book, there's plenty more features and interesting things that I won't be able to cover unless I write a complete book on TypeScript. 

If you are interested into learning more about all the cool stuff that you can do with TypeScript type annotations then let me insist once more in the [TypeScript handbook](http://bit.ly/ts-handbook) and at the [release notes](http://bit.ly/ts-whats-new).

## Working with TypeScript in Real World Applications

So TypeScript is great, it gives you lots of great new features on top of ES6 and an awesome developer experience via type annotations, but how do you start using it in real world applications?

The good news is that you'll rarely need to create a TypeScript setup from scratch. The most popular front-end frameworks have built-in support for TypeScript. For instance, TypeScript is the main language of choice for Angular and starting a new project with Angular and TypeScript is as easy as using the Angular cli and typing:

```bash
$ ng new my-new-app
```

Likewise using React and the *Create React App* tool (also known as CRA) starting a React project with TypeScript takes only typing[^react-starter]:

```bash
$ create-react-app my-new-app --scripts-version=react-scripts-ts
```

[^react-starter]: This command uses the TypeScript React Started in the background http://bit.ly/ts-react-starter

If you use any of these options above you're good to go. In either case a new app will be bootstrapped for you and you'll be able to start building your Angular or React app with TypeScript.

On the other hand, if you, for some reason, need to start from scratch you'll find that there are [TypeScript plugins](http://bit.ly/ts-plugins) for the most common task managers or module bundlers like grunt, gulp or webpack. While integrating TypeScript into your tool chain there's one additional step that you may need to take in order to configure the TypeScript compiler: setting up your `tsconfig` file.

### The `tsconfig.json` File

The `tsconfig.json` file contains the TypeScript configuration for your project. It tells the TypeScript compiler about all the details it needs to know to compile your project like:

* Which files to transpile
* Which files to ignore
* Which version of JavaScript to use as a target of the transpilation
* Which module system to use in the output JavaScript
* How strict the compiler should be. Should it allow implicit any? Should it perform strict null checks?
* Which third-party libraries types to load

If you don't specify part of the information, the TypeScript compiler will try to do its best. For instance, not specifying any files to transpile will prompt the TypeScript compiler to transpile all TypeScript files (`*.ts`) within the project folder. Not specifying any third-party types will lead the TypeScript compiler to look for type definition files within your project (f.i. within `./node_modules/@types`).

This is an example `tsconfig.json` from the TypeScript documentation that can give you an idea:

```json
{
    "compilerOptions": {
        "module": "system",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "outFile": "../../built/local/tsc.js",
        "sourceMap": true
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules",
        "**/*.spec.ts"
    ]
}
```

For a full reference of all the available options take a look at the [TypeScript documentation](http://bit.ly/tsc-options).

> ### In This Chapter's Examples We Didn't Use A tsconfig. How Come?
>
> The TypeScript compiler `tsc` has two different modes of operation: with or without input files. 
> When you don't specify input files while executing `tsc` the TypeScript compiler will try to find an available `tsconfig.json` file with its configuration. 
> When you do specify input files the TypeScript compiler will ignore `tsconfig.json`. That is why in previous sections we didn't need to define a `tsconfig.json` file when we run `tsc hello-wizard.ts`.

### TypeScript and Third Party Libraries

Starting from TypeScript 2.0 installing type declarations for third party libraries is as easy as installing any other library via `npm`. 

Imagine that you want to take advantage of [ramda.js](http://ramdajs.com/) a library with helpful utility functions with a strong functional programming flavor that we'll see in-depth in the functional programming tome of JavaScript-mancy. 

You can add the library to your TypeScript project using npm:

```bash
# create package.json
$ npm init 

# install ramda and save dependency
$ npm install --save ramda
```

And you can install the type declarations for that library using `@types/<name-of-library-in-npm>`:

```bash
$ npm install --save-dev @types/ramda
```

Now when you start working on your project within Visual Studio Code or your editor of choice you should get full type support when using ramda.js. Try writing the snippet below and verify how TypeScript helps you along the way:

```bash
import { add } from 'ramda';

const add5 = add(5);

console.log(`5 + 5: ${add5(5)}`);
console.log(`5 + 10: ${add5(1)}`);
```

All these type definitions come from the [DefinitelyTyped](http://definitelytyped.org/) project and are pushed periodically to npm under the `@types/` prefix as a convention. If you can't find the type declarations for a particular library use the [TypeSearch](http://bit.ly/ts-search) web app to find it (You can try `stampit` from the stamps chapter section for instance).

## Concluding

And that is TypeScript! This was the longest chapter in the book but I hope that it was entertaining and interesting enough to carry you to the end. Let's make a quick recap so you get a quick reminder that'll help you remember all the TypeScript awesomeness you've just learned.

TypeScript is a superset of JavaScript that includes a lot of ESnext features and type annotations. By far, the defining feature of TypeScript are its use of types. Type annotations allow you to provide additional metadata about your code that can be used by the TypeScript compiler to provide a better developer experience for you and your team at the expense of code verbosity.

TypeScript is a superset of ES6 and expands on its features with a lot of ESnext improvements and TypeScript specific features. We saw several ESnext features like class members and the new Objects spread and rest operators. We also discovered how TypeScript enhances classes with parameter properties and property accessors, and brings a new Enum type that allows you to write more intentional code.

Type Annotations are TypeScript's bread and butter. TypeScript extends JavaScript with new syntax and semantics that allow you to provide rich information about your application types. In addition to being able to express primitive types, TypeScript introduces interfaces, generics, intersection and union types, aliases, type guards, etc... All of these mechanisms allow you to do a new type of meta-programming that lets you improve your development experience via type annotations. Still adding type annotations can be a little daunting and a lot of work, in order to minimize this, TypeScript attempts to infer as much typing as it can from your code.

In the spirit of JavaScript and duck-typing, TypeScript has a structural typing system. This means that types will be equivalent if they share the same structure, that is, if they have the same properties. This is opposed to nominal typing systems like the ones used within C# or Java where type equivalence is determined by explicitly implementing types. Structural typing is great because it gives you a lot of flexibility and, at the same time, great compile-time error detection and improved tooling.

In the front-end development world we're seeing an increased adoption of TypeScript, particularly, as it has become the core language for development in Angular. Moreover, it is also available in most of the common front-end frameworks, IDEs, tex-editors and front-end build tools. It is also well supported in third-party libraries through type definitions and the DefinitelyTyped project, and installing type definitions for a library is as easy as doing an `npm install`.

From a personal perspective, one of the things I enjoyed the most about JavaScript coming from the world of C# was its terseness and the lack of ceremony and unnecessary artifacts. All of the sudden, I didn't need to write `PurchaseOrder purchaseOrder` or `Employee employee` any more, an employee was an `employee`, *period*. I didn't need to write a seemingly infinite amount of boilerplate code to make my application flexible and extensible, or fight with the language to bend it to my will, things just worked. As I saw the release of TypeScript I worried about JavaScript losing its soul and becoming a language as rigid as C# or Java. After experiencing TypeScript developing Angular applications, its optional typing, the great developer experience and, above all, the fact that it has structural typing I am hopeful. It'll be interesting to follow its development in the upcoming months and years. It may well be that all of us will end up writing TypeScript for a living.

> ```javascript
> mooleen.says('You shall only use types!?...');
> 
> bandalf.says("I've got my magic back... " + 
>   "but for some reason it won't... work");
>
> mooleen.says("I, too, can feel the bond with the " +
>   "currents of magic again");
>
> randalf.says("The Order of the Red Moon...");
>
> red.says("There are our weapons! Under the obelisk!");
> 
> /*
> The group makes a precarious circle beside the obelisk as
> the hordes of lizard-like beast surround them.
> */
>
> randalf.says("types... Yes! " + 
>   "Now I remember, The Last Stand and the Sacred Order. " +
>   "Their story lies between history and legend. " +
>   "It is said that they cultivated an obscure " +
>   "flavor of JavaScriptmancy. The legends say that " +
>   "they expanded it and enriched it with types...");
>
> bandalf.says("Excellent. And what does that mean?");
>
> rat.says("It means we're dead");
> red.says("A glorious death!");
>
> randalf.says("Well they were a very guarded Order " +
>   "and they were exterminated to the last woman " + 
>   "in The Last Stand or so the story says..." + 
>   "In the deep jungles of Azons.");
>
> mooleen.whispers("Azons...");
> 
> /* 
>   The sisters surround her on the battlements,
>   all wearing the black of the order in full armor.
>   The fort has an excellent view of the thick,
>   beautiful jungle below and of the unending hosts
>   of lizardmen surrounding them.
>   The Grand Commander shouts: 'To Arms sisters!'
>   'For one last time!'
> */
> 
> mooleen.says("Types... Types... Types!");
> mooleen.says("I remember...");
> ```

## Exercises

> ### Experiment JavaScriptmancer!
>
> You can experiment with these exercises and some possible solutions downloading the source code from [GitHub](https://github.com/vintharas/javascriptmancy-code-samples).
>

> ### Earn Some Time! A wall of ice!
> 
> The beasts are quickly approaching, gain some breathing room by erecting an ice wall between them and the group. The wall should be at least `100` feet high, `7` feet deep and `700` feet long to be able to surround the group.
>
> The Wall should satisfy the following snippet:
> 
> ```javascript
> const iceWall = new Wall(MagicElement.Ice, {
>                           height: 100,
>                           depth: 7, 
>                           length: 700});
> 
> console.log(iceWall.toString());
> // => A wall of frozen ice. It appears to be about 100 feet high
> //    and extends for what looks like 700 feet.
> 
> iceWall.element = MagicElement.Fire;
> // => [ts] Cannot assign to 'element' because it is 
> //         a constant or a read-only property.
> iceWall.wallOptions.height = 100;
> // => [ts] Cannot assign to 'height' because it is 
> //         a constant or a read-only property.
> ```
>
> Hint: You can use an enum to represent the `MagicElement`, an interface to represent the `WallSpecifications` and a class for the `Wall` itself. Remember to add type annotations!

> ### Solution
>
> ```javascript
> 
> enum MagicElement {
>   Fire = "fire",
>   Water = "water",
>   Earth = "earth",
>   Air = "windy air",
>   Stone = "hard stone",
>   Ice = "frozen ice"
> }
> 
> interface WallSpecs{
>   readonly height: number,
>   readonly depth: number,
>   readonly length: number
> }
> 
> class Wall {
>   constructor(readonly element: MagicElement, 
>               readonly specs: WallSpecs){ }
> 
>   toString(){
>     return `A wall of ${this.element}. It appears to be about ` +
>       `${this.specs.height} feet high and extends for what ` +
>       `looks like ${this.specs.length} feet.`;
>   }
> }
> 
> const iceWall = new Wall(MagicElement.Ice, {
>                           height: 100,
>                           depth: 7, 
>                           length: 700});
> 
> console.log(iceWall.toString());
> // => A wall of frozen ice. It appears to be about 100 feet high
> //    and extends for what looks like 700 feet long.
> 
> // iceWall.element = MagicElement.Fire;
> // => [ts] Cannot assign to 'element' because it is 
> //         a constant or a read-only property.
> // iceWall.wallOptions.height = 100;
> // => [ts] Cannot assign to 'height' because it is 
> //         a constant or a read-only property.
> 
> world.randalf.gapes()
> // => Randalf gapes
> 
> world.randalf.says('How?');
> world.mooleen.says('I just remembered...');
> 
> world.randalf.says('Remember?');
> world.randalf.says("You look very young for being millennia old");
> 
> world.mooleen.shrugs();
> // => Moleen shrugs
> world.mooleen.says("Brace yourselves... they're coming " + 
>   "beware if they open their jaws and seem to catch breath " +
>   "they breathe fire");
> ```

> ### Freeze The Lizards!
> 
> You've earned some time. Now you can take this breather to observe the lizards, model them appropriately and craft a `frost` spell that will send them to the lizard frozen hell.
>
> This is what you can observe:
>
> ```javascript
> giantLizard.jumps();
> // => The giant lizard gathers strength in its 
> //    4 limbs and takes a leap through the air
> giantLizard.attacks(red);
> // => The giant lizard attacks Red with great fury
> giantLizard.breathesFire(red);
> // => The giant lizard opens his jaws unnaturally wide
> //    takes a breath and breathes a torrent of flames
> //    towards Red
> giantLizard.takeDamage(Damage.Physical, 20);
> // => The giant lizard has extremely hard scales
> //    that protect it from physical attacks (Damage 50%)
> //    You damage the giant lizard (-10hp)
> giantLizard.takeDamage(Damage.Cold, 20);
> // => The giant lizard is very sensitive to cold.
> //    It wails and screams. (Damage 200%)
> //    You damage the giant lizard (-40hp)
> ```
>
> Create a `frost` spell that fulfills this snippet:
>
> ```javascript
> frost(giantLizard, /* mana */ 10);
> // => The air surrounding the target starts quickly forming a
> //    frozen halo as the water particles start congealing.
> //    All of the sudden it explodes into freezing ice crystals
> //    around the giant lizard.
> //    The giant lizard is very sensitive to cold.
> //    It wails and screams. (Damage 200%)
> //    You damage the giant lizard (-2000hp)
> ```
>
> Hint: Create a interface using the observations above and use that new type in your `frost` function. Reflect about the required contract to cause damage on an enemy.

> ### Solution
>
> ```javascript
> 
> enum DamageType {
>   Physical,
>   Ice,
>   Fire,
>   Poison
> }
> 
> // We only need an interface that
> // describes something that can be damaged
> interface Damageable{
>   takeDamage(damageType: DamageType, damage: number);
> }
> 
> function frost(target: Damageable, mana: number){
>   // from the example looks like damage 
>   // can be calculated based on mana
>   const damage = mana * 100;
>   console.log(
>     `The air surrounding the target starts quickly forming a ` + 
>     `frozen halo as the water particles start congealing. ` +
>     `All of the sudden it explodes into freezing ice crystals ` +
>     `around the ${target.toString()}.`);
>   target.takeDamage(DamageType.Ice, damage);
> }
> 
> console.log('A giant lizard leaps inside the wall!');
> // this method returns a Lizard object (see samples)
> const giantLizard = world.getLizard();
> 
> world.mooleen.says('And that is as far as you go');
> 
> frost(giantLizard, /* mana */ 2);
> // => The air surrounding the target starts quickly forming a 
> //    frozen halo as the water particles start congealing. 
> //    All of the sudden it explodes into freezing ice crystals 
> //    around the giant lizard.
> //    The giant lizard is very sensitive to cold.
> //    It wails and screams. (Damage 200%)
> //    You damage the giant lizard (-400hp)
> //    The giant lizard dies.
> 
> world.mooleen.laughsWithGlee();
> // => Mooleen laughs with Glee
> 
> /* 
> More and more lizards make it into the fortified area.
> Mooleen, Red, randalf and bandalf form a semicircle against
> the obsidian obelisk and fight fiercely for every inch.
> When the lizards are about to overwhelm the group a huge furry
> figure flashes in front of them charging through the lizard 
> front line and causing enough damage to let the company regroup.
> */
> 
> world.mooleen.says('What?');
> world.rat.says('Happy to serve!');
> 
> world.mooleen.says('You can do that?!');
> world.rat.says('Err... we familiars are very flexible creatures');
> 
> world.mooleen.says("Why didn't you say it before?");
> world.rat.says("Oh... the transformation is incredibly painful");
> world.rat.says("And I bet you'd want to ride on my back." + 
>     "I'm not putting up with that");
> ```

> ### Wholesale Destruction!
> 
> Killing the beasts one by one won't cut it. We need a more powerful spell that can annihilate them in groups. Design an `iceCone` spell that can impact several targets at once.
>
> It should fulfill the following snippet of code:
>
> ```javascript
> iceCone(lizard, smallerLizard, greaterLizard);
> // => Cold ice crystals explode from the palm of your hand
> //    and impact the lizard, smallerLizard, greaterLizard.
> //    The lizard is very sensitive to cold.
> //    It wails and screams. (Damage 200%)
> //    You damage the giant lizard (-500hp)
> //    The smaller lizard is very sensitive to cold.
> //    It wails and screams. (Damage 200%)
> //    You damage the giant lizard (-500hp)
> //    etc...
> ```
>
> Hint: you can use rest parameters and array type annotations!

> ### Solution
>
> ```javascript
> function iceCone(...targets: Damageable[]){
>   const damage = 500;
>   console.log(`
> Cold ice crystals explode from the palm of your hand
> and impact the ${targets.join(', ')}.`);
>   for(let target of targets) {
>     target.takeDamage(DamageType.Ice, damage);
>   }
> }
> 
> iceCone(getLizard(), getLizard(), getLizard());
> // => Cold ice crystals explode from the palm of your hand
> // and impact the giant lizard, giant lizard, giant lizard.
> // The giant lizard is very sensitive to cold.
> // It wails and screams. (Damage 200%)
> // You damage the giant lizard (-1000hp)
> // The giant lizard dies.
> // etc...
> 
> world.mooleen.says('Yes!');
> 
> /* 
> Mooleen looks around. She's fending off the lizards fine but
> her companions are having some problems. 
> 
> Red is deadly with the lance and shield but his lance, 
> in spite of of his massive strength, hardly penetrates
> the lizards' thick skin. 
> 
> Bandalf is slowly catching up and crafting ice spells 
> and Randalf, though, a master with the quarterstaff can
> barely fend off the attacks from a extremely huge lizard.
> 
> Things start to look grimmer and grimmer as more lizards jump over
> the wall around the obelisk.
> */
> 
> world.mooleen.says('I need to do something quick');
> ```

> ### Empower Your Companions with Enchantments!
> 
> Things are looking grim. Your only chance is to empower your companions so that you can offer a strong united front against the growing host of enemies. Craft an `enchant` spell that can enchant weapons and armor with elemental properties.
>
> The `enchant` spell should satisfy the following snippet of code:
>
> ```javascript
> quarterstaff.stats();
> // => Name: Crimson Quarterstaff
> // => Damage Type: Physical
> // => Damage: d20
> // => Bonus: +20
> // => Description: A quarterstaff of pure red
>
> enchant(quarterstaff, MagicElement.Ice);
> // => You enchant the Crimson Quarterstaff with a frozen 
> //    ice incantation
> //    The weapon gains Ice damage and +20 bonus damage
>
> quarterstaff.stats();
> // => Name: Crimson Quarterstaff
> // => Damage Type: Ice
> // => Damage: d20
> // => Bonus: +40
>
> cloak.stats();
> // => Name: Crimson Cloak
> // => Type: cloak
> // => Protection: 20
> // => ElementalProtection: none
> // => Description: A cloak of pure red
>
> enchant(cloak, MagicElement.Fire);
> // => You enchant the Crimson Cloak with a fire incantation 
> //    The Crimson Cloak gains +20 fire protection
>
> cloak.stats();
> // => Name: Crimson Cloak
> // => Type: cloak
> // => Protection: 20
> // => ElementalProtection: Fire (+20)
> // => Description: A cloak of pure red
> ```
>
> Hint: Use union types and type guards within the `enchant` spell to allow it to enchant both `Weapon` and `Armor`

> ### Solution
>
> ```javascript
> 
> class Weapon {
>   constructor(public name: string,
>               public damageType: DamageType,
>               public damage: number,
>               public bonusDamage: number,
>               public description: string){}
>   stats(){
>     return `
> Name: ${this.name}
> Damage Type: ${this.damageType}
> Damage: d${this.damage}
> Bonus: +${this.bonusDamage}
> Description: ${this.description}
>       `;
>   }
> 
>   toString() { return this.name; }
> }
> 
> enum ArmorType {
>   Cloak = 'cloak',
>   Platemail = 'plate mail'
> }
> 
> interface ElementalProtection {
>   damageType: DamageType;
>   protection: number;
> }
> 
> class Armor {
>   elementalProtection: ElementalProtection[] = [];
>   constructor(public name: string,
>               public type: ArmorType,
>               public protection: number,
>               public description: string){}
>   stats(){
>     return `
> Name: ${this.name}
> Type: ${this.type}
> Protection: ${this.protection}
> ElementalProtection: ${this.elementalProtection.join(', ') || 'none'}
> Description: ${this.description}
>       `;
>   }
>   toString() { return this.name; }
> }
> 
> function enchant(item: Weapon | Armor, element: MagicElement){
>   console.log(`You enchant the ${item} with a ${element} incantation`);
>   if (item instanceof Weapon){
>     enchantWeapon(item, element);
>   } else{
>     enchantArmor(item, element);
>   }
>
>   function enchantWeapon(weapon: Weapon, element: MagicElement){
>     const bonusDamage = 20;
>     weapon.damageType = mapMagicElementToDamage(element);
>     weapon.bonusDamage += bonusDamage;
>     console.log(`The ${item} gains ${bonusDamage} ` + 
>                 `${weapon.damageType} damage`);
>   }
>   function enchantArmor(armor: Armor, element: MagicElement){
>     const elementalProtection = {
>       damageType: mapMagicElementToDamage(element),
>       protection: 20,
>       toString(){ return `${this.damageType} (+${this.protection})`}
>     };
>     armor.elementalProtection.push(elementalProtection);
>     console.log(`the ${item} gains ${elementalProtection.protection}` + 
>                 ` ${elementalProtection.damageType} incantation`);
>   }
> }
> 
> function mapMagicElementToDamage(element: MagicElement){
>   switch(element){
>     case MagicElement.Ice: return DamageType.Ice;
>     case MagicElement.Fire: return DamageType.Fire;
>     default: return DamageType.Physical;
>   }
> }
> 
> let quarterstaff = getQuarterstaff();
> console.log(quarterstaff.stats());
> // => Name: Crimson Quarterstaff
> //    Damage Type: Physical
> //    Damage: d20
> //    Bonus: +20
> //    Description: A quarterstaff of pure red
> 
> enchant(quarterstaff, MagicElement.Ice);
> // => You enchant the Crimson Quarterstaff with a frozen ice incantation
> //    The Crimson Quarterstaff gains 20 Ice damage
> 
> console.log(quarterstaff.stats());
> // Name: Crimson Quarterstaff
> // Damage Type: Ice
> // Damage: d20
> // Bonus: +40
> // Description: A quarterstaff of pure red
> 
> let cloak = getCloak();
> console.log(cloak.stats());
> // Name: Crimson Cloak
> // Type: cloak
> // Protection: 20
> // ElementalProtection: none
> // Description: A cloak of pure red
> 
> enchant(cloak, MagicElement.Fire);
> // You enchant the Crimson Cloak with a fire incantation
> // the Crimson Cloak gains 20 Fire incantation
> 
> console.log(cloak.stats());
> // Name: Crimson Cloak
> // Type: cloak
> // Protection: 20
> // ElementalProtection: Fire (+20)
> // Description: A cloak of pure red
> 
> world.mooleen.says('Awesome! This will do!');
> 
> /*
> 
> As soon as Mooleen enchants the group's weapons and
> armor the battle takes a different turn. Where previously
> a lizard would've remained impassible after receiving a wound
> now there's wails and shouts of beast pain surrounding 
> the group...
> 
> */
> 
> world.mooleen.says('haha! To Arms Sisters!');
> world.red.says('What?');
> ```