TypeScript: JavaScript + Types = Awesome Developer Productivity 🔥 🔥 🔥

TypeScript: JavaScript + Types = Awesome Developer 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....

This article is a chapter from JavaScript-mancy OOP: Mastering the Arcane Art of Summoning Objects in JavaScript 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
/* 
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 or downloading the source code from GitHub.
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:

var manaReserves = 10;

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

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

So we go and write the following:

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

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

// => 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 rechargeManain TypeScript would have automatically resulted in a compiler error that would've read:

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:

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:

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:

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:

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:

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:

// [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 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 anywhich 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 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.

The easiest way to get started is to install node and npm in your development computer. Once you've done that, we'll install the TypeScript compiler using npm:

$ npm install -g typescript

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

$ tsc -v
Version 2.4.2

And accessing the TypeScript compiler help:

$ 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 during these examples but you're welcome to use any editor that you prefer.

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

$ code hello-wizard.ts

Let's write the canonical hello wizard in TypeScript with a sayHellofunction:

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:

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:

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:

$ 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:

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:

$ 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:

$ 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.## 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.> 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:

// 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:

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:

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 @readonlydecorator 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:

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:

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:

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:

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:

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:

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:

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:

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

And now we can rewrite our previous example:

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:

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:

// 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 typeprovided 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.

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:

// 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:

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:

// 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:

// 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:

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

Instead it will be inlined and any reference to Fire, Water, Air and Earthwill 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:

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

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

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:

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#.

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:

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!

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

Or cloning them:

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:

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:

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 <em>wizard</em>, <em>canBeIdentifiedByName</em> and <em>canCastSpells</em> 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:

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:

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 and at the release notes 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:

// 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:

// 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:

// 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:

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 hitPointsproperty of type number. We can cast a frost spell on a dangerous foe that must comply with the required contract - that of having a hitPointsproperty:

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:

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:

interface Minion {
    hitPoints: number;
}

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

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, interfacesare 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:

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!

// 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 Towerand has a hitPoints and a defense property it seems to work as well:

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:

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:

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?

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 Minionor 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):

// 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:

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:

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:

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:

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:

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:

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:

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

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

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:

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:

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:

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:

interface NumberArray {
  push(n: number);
  pop(): number;

  // etc
}

interface StringArray {
  push(s: string);
  pop(): string;

  // etc
}

// etc...

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

// note that `Array<T>` is already a built-in type in TypeScript
interface Array<T>{
  push(s: T);
  pop(): T;

  // etc
}

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

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:

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:

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

And now this will be a perfectly usable box:

let box: ConstrainedCell<MagicCreature>;

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

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:

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:

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:

WizardProps & NameMixin & SpellMixin

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

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:

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:

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

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

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

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:

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 typeofthat 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?

WizardProps & NameMixin & SpellMixin

You can create an alias Wizard and use that instead:

type Wizard = WizardProps & NameMixin & SpellMixin;

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

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 and at the release notes.

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:

$ 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]:

$ 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 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:

{
    "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.

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 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:

# 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>:

$ 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:

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 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 TypeSearchweb 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.

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.### 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:

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


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:

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:

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


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:

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

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:

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


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?');

What is JavaScript – All You Need To Know About JavaScript

What is JavaScript – All You Need To Know About JavaScript

In this article on what is JavaScript, we will learn the basic concepts of JavaScript.

After decades of improvement, JavaScript has become one of the most popular programming languages of all time. It all started in the year 1995 when Brendan Eich created JavaScript in a span of 10 days. Since then, it has seen multiple versions, updates and has grown to the next level.

Here’s a list of topics that I’ll be covering in this blog:

  1. What is JavaScript
  2. What can JavaScript do?
  3. JavaScript Frameworks
  4. The Big Picture: HTML, CSS & JavaScript
  5. Benefits of JavaScript
  6. Fundamentals of JavaScript
    VariablesConstantsData TypesObjectsArraysFunctionsConditional statementsLoopsSwitch case
What is JavaScript?

JavaScript is a high level, interpreted, programming language used to make web pages more interactive.

Have you ever thought that your website is missing something? Maybe it’s not engaging enough or it’s not as creative as you want it to be. JavaScript is that missing piece which can be used to enhance web pages, applications, etc to provide a more user-friendly experience.

What is JavaScript?

JavaScript is the language of the web, it is used to make the web look alive by adding motion to it. To be more precise, it’s a programming language that let’s you implement complex and beautiful things/design on web pages. When you notice a web page doing more than just sit there and gawk at you, you can bet that the web page is using JavaScript.

Feature of JavaScript

Scripting language and not Java: In fact, JavaScript has nothing to do with Java. Then why is it called “Java” Script? When JavaScript was first released it was called Mocha, it was later renamed to LiveScript and then to JavaScript when Netscape (founded JavaScript) and Sun did a license agreement. Object-based scripting language which supports polymorphism, encapsulation and to some extent inheritance as well.**Interpreted language: **It doesn’t have to be compiled like Java and C which require a compiler.JavaScript runs in a browser: You can run it on Google Chrome, Internet Explorer, Safari, etc. JavaScript can execute not only in the browser but also on the server and any device which has a JavaScript Engine.

What is JavaScript – Stackoverflow stats

Currently, we have 100s of programming languages and every day new languages are being created. Among these are few powerful languages that bring about big changes in the market and JavaScript is one of them.

JavaScript has always been on the list of popular programming languages. According to StackOverflow, for the 6th year in a row, JavaScript has remained the most popular and commonly used programming language.

What can JavaScript do?

JavaScript is mainly known for creating beautiful web pages & applications. An example of this is Google Maps. If you want to explore a specific map, all you have to do is click and drag with the mouse. And what sort of language could do that? You guessed it! It’s JavaScript.JavaScript can also be used in smart watches. An example of this is the popular smartwatch maker called Pebble. Pebble has created Pebble.js which is a small JavaScript Framework that allows a developer to create an application for the Pebble line of watches in JavaScript.

What is JavaScript – Applications of JavaScript
Most popular websites like Google, Facebook, Netflix, Amazon, etc make use of JavaScript to build their websites.Among things like mobile applications, digital art, web servers and server applications, JavaScript is also used to make Games. A lot of developers are building small-scale games and apps using JavaScript.## JavaScript Frameworks

One major reason for the popularity of JavaScript is the JavaScript Frameworks. Here’s a brief introduction of the most trending JavaScript frameworks :

  1. AngularJS is Google’s web development framework which provides a set of modern development and design features for rapid application development.

  2. ReactJS is another top JavaScript framework mainly maintained by Facebook and it’s behind the User Interface of Facebook and Instagram, showing off its efficiency in maintaining such high traffic applications.

What is JavaScript – JavaScript Frameworks

  1. MeteorJS is mainly used for providing back-end development. Using JavaScript on the back-end to save time and build expertise is one of the major ideas behind Meteor.

  2. jQuery can be used when you want to extend your website and make it more interactive. Companies like Google, WordPress and IBM rely on jQuery.

The Big Picture: HTML, CSS & JavaScript

Anyone familiar with JavaScript knows that it has something to do with HTML and CSS. But what is the relationship between these three? Let me explain this with an analogy.

What is JavaScript – HTML, CSS and JavaScript

Think of HTML (HyperText Markup Language) as the skeleton of the web. It is used for displaying the web.

On the other hand, CSS is like our clothes. We put on fashionable clothes to look better. Similarly, the web is quite stylish as well. It uses CSS which stands for Cascading Style Sheets for styling purpose.

Then there is JavaScript which puts life into a web page. Just like how kids move around using the skateboard, the web also motions with the help of JavaScript.

Benefits of JavaScript

There has to be a reason why so many developers love working on JavaScript. Well, there are several benefits of using JavaScript for developing web applications, here’s a few benefits:

It’s easy to learn and simple to implement. It is a weak-type programming language unlike the strong-type programming languages like Java and C++, which have strict rules for coding.

It’s all about being fast in today’s world and since JavaScript is mainly a client-side programming language, it is very fast because any code can run immediately instead of having to contact the server and wait for an answer.

Rich set of frameworks like AngularJS, ReactJS are used to build web applications and perform different tasks.

**Builds interactive websites: **We all get attracted to beautifully designed websites and JavaScript is the reason behind such attractive websites and applications.

JavaScript is an interpreted language that does not require a compiler because the web interprets JavaScript. All you need is a browser like Google Chrome or Internet Explorer and you can do all sorts of stuff in the browser.

JavaScript is platform independent and it is supported by all major browsers like Internet Explorer, Google Chrome, Mozilla Firefox, Safari, etc.

JavaScript Fundamentals

In this What is JavaScript blog, we’ll cover the following basic fundamentals of JavaScript
VariablesConstantsData TypesObjectsArraysFunctionsConditional statementsLoopsSwitch case## Variables

Variable is a name given to a memory location which acts as a container for storing data temporarily. They are nothing but reserved memory locations to store values.

What is JavaScript – Variables

To declare a variable in JavaScript use the ‘let’ keyword. For example:

let age;
age=22;

In the above example, I’ve declared a variable ‘age’ by using the ‘let’ keyword and then I’ve stored a value (22) in it. So here a memory location is assigned to the ‘age’ variable and it contains a value i.e. ’22’.

Constants

Constants are fixed values that don’t change during execution time.

To declare a constant in JavaScript use the ‘const’ keyword. For example:

const mybirthday;
mybirthday='3rd August'; 

Data types

You can assign different types of values to a variable such as a number or a string. In JavaScript, there are two categories of data types :

What is JavaScript – Data Types

Objects

An object is a standalone entity with properties and types and it is a lot like an object in real life. For example, consider a girl, whose name is Emily, age is 22 and eye-color is brown. In this example the object is the girl and her name, age and eye-color are her properties.

What is JavaScript – Objects example

Objects are variables too, but they contain many values, so instead of declaring different variables for each property, you can declare an object which stores all these properties.

To declare an object in JavaScript use the ‘let’ keyword and make sure to use curly brackets in such a way that all property-value pairs are defined within the curly brackets. For example:

let girl= {
name: 'Emily',
age: 22,
eyeColour: 'Brown'
};

In the above example, I’ve declared an object called ‘girl’ and it has 3 properties (name, age, eye colour) with values (Emily, 22, Brown).

Arrays

An array is a data structure that contains a list of elements which store multiple values in a single variable.

For example, let’s consider a scenario where you went shopping to buy art supplies. The list of items you bought can be put into an array.

What is JavaScript – Arrays example

To declare an array in JavaScript use the ‘let’ keyword with square brackets and all the array elements must be enclosed within them. For example:

let shopping=[];
shopping=['paintBrush','sprayPaint','waterColours','canvas'];

In the above example I’ve declared an array called ‘shopping’ and I’ve added four elements in it.

Also, array elements are numbered from zero. For example this is how you access the first array element:

shopping[0];		

Functions

A function is a block of organised, reusable code that is used to perform single, related action.

Let’s create a function that calculates the product of two numbers.

To declare a function in JavaScript use the ‘function’ keyword. For example:

function product(a, b) {
return a*b;
}

In the above example, I’ve declared a function called ‘product’ and I’ve passed 2 parameters to this function, ‘a’ and ‘b’ which are variables whose product is returned by this function. Now, in order to call a function and pass a value to these parameters you’ll have to follow the below syntax:

product(8,2);

In the above code snippet I’m calling the product function with a set of values (8 & 2). These are values of the variables ‘a’ and ‘b’ and they’re called as arguments to the function.

Conditional statements – if

Conditional statement is a set of rules performed if a certain condition is met. The ‘if’ statement is used to execute a block of code, only if the condition specified holds true.

What is JavaScript – if flowchart

To declare an if statement in JavaScript use the ‘if’ keyword. The syntax is:

if(condition) {
statement;
}

Now let’s look at an example:

let numbers=[1,2,1,2,3,2,3,1];
if(numbers[0]==numbers[2]) {
console.log('Correct!');
}

In the above example I’ve defined an array of numbers and then I’ve defined an if block. Within this block is a condition and a statement. The condition is ‘(numbers[0]==numbers[2])’ and the statement is ‘console.log(‘Correct!’)’. If the condition is met, only then the statement will be executed.

Conditional statements- Else if

Else statement is used to execute a block of code if the same condition is false.

What is JavaScript – Else-if flowchart

The syntax is:

if(condition) {
statement a;
}
else (condition) {
statement b;
}

Now let’s look at an example:

let numbers=[1,2,1,2,3,2,3,1];
if(numbers[0]==numbers[4] {
console.log("Correct!");
}
else {
console.log("Wrong, please try again");
}

In the above example, I’ve defined an if block as well as an else block. So if the conditions within the if block holds false then the else block gets executed. Try this for yourself and see what you get!

**Loops **

Loops are used to repeat a specific block until some end condition is met. There are three categories of loops in JavaScript :

  1. while loop
  2. do while loop
  3. for loop
While loop

While the condition is true, the code within the loop is executed.

What is JavaScript – while loop flowchart

The syntax is:

while(condition) {
loop code;
}

Now let’s look at an example:

let i=0;
while(i < 5) {
console.log("The number is " +i);
i++;
}

In the above example, I’ve defined a while loop wherein I’ve set a condition. As long as the condition holds true, the while loop is executed. Try this for yourself and see what you get!

Do while loop

This loop will first execute the code, then check the condition and while the condition holds true, execute repeatedly.

What is JavaScript – Do while loop flowchart

Refer the syntax to better understand it:

do {
loop code;
} while(condition);

This loop executes the code block once before checking if the condition is true, then it will repeat the loop as long as the condition holds true.

Now let’s look at an example:

do {
console.log("The number is " +i);
i++;
}
while(i > 5);

The above code is similar to the while loop code except, the code block within the do loop is first executed and only then the condition within the while loop is checked. If the condition holds true then the do loop is executed again.

For loop

The for loop repeatedly executes the loop code while a given condition is TRUE. It tests the condition before executing the loop body.

What is JavaScript – for loop flowchart

The syntax is:

for(begin; condition; step) {
loop code;
}

In the above syntax:

  • begin statement is executed one time before the execution of the loop code
  • condition defines the condition for executing the loop code
  • step statement is executed every time after the code block has been executed

For example:

for (i=0;i<5;i++) {
console.log("The number is " +i);
}

In the above example, I’ve defined a for loop within which I’ve defined the begin, condition and step statements. The begin statement is that ‘i=0’. After executing the begin statement the code within the for loop is executed one time. Next, the condition is checked, if ‘i<5’ then, the code within the loop is executed. After this, the last step statement (i++) is executed. Try this and see what you get!

Switch Case

The switch statement is used to perform different actions based on different conditions.

What is JavaScript – Switch case flowchart

Let’s look at the syntax for switch case:

switch(expression) {
case 1:
code block 1
break;
case 2:
code block 2
break;
default:
code block 3
break;
}

How does it work?

  • Switch expression gets evaluated once
  • Value of the expression is compared with the values of each case
  • If there is a match, the associated block of code is executed

Let’s try this with an example:

let games='football';
switch(games) {
case "throwball":
console.log("I dislike throwball!");
break;
case "football":
console.log("I love football!");
break;
case "cricket":
console.log("I'm a huge cricket fan!");
break;
default:
console.log("I like other games");
break;
}

In the above example the switch expression is ‘games’ and the value of games is ‘football’. The value of ‘games’ is compared with the value of each case. In this example it is compared to ‘throwball’, ‘cricket’ and ‘football’. The value of ‘games’ matches with the case ‘football’, therefore the code within the ‘football’ case is executed. Try this for yourself and see what you get!

With this, we come to the end of this blog. I hope you found this blog informative and I hope you have a basic understanding of JavaScript. In my next blog on JavaScript I’ll be covering in-depth concepts, so stay tuned.

Also, check out our video on JavaScript Fundamentals if you want to get started as soon as possible and don’t forget to leave a comment if you have any doubt and also, let us know whether you’d want us to create more content on JavaScript. We are listening!

Learn JavaScript in 60 Minutes | JavaScript Crash Course | JavaScript Tutorial |

This video on "JavaScript" will help you learn JavaScript basics and fundamental concepts in 60 minutes. This will provide you in-depth knowledge about the JavaScript fundamentals that will help you write your own code in JavaScript and build a website. This JavaScript tutorial covers following topics..

==================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

Svelte.js - The Complete Guide

The Complete JavaScript Course 2019: Build Real Projects!

Advanced CSS and Sass: Flexbox, Grid, Animations and More!

CSS - The Complete Guide (incl. Flexbox, Grid & Sass)

CSS Bootcamp - Master CSS (Including CSS Grid / Flexbox)

Build Responsive Real World Websites with HTML5 and CSS3

Become a JavaScript developer - Learn (React, Node,Angular)

JavaScript: Understanding the Weird Parts

Vue JS 2 - The Complete Guide (incl. Vue Router & Vuex)

The Full JavaScript & ES6 Tutorial - (including ES7 & React)

JavaScript - Step By Step Guide For Beginners

JavaScript | How to use classes in JavaScript

JavaScript | How to use classes in JavaScript

Classes in JavaScript are a special syntax for its prototypical inheritance model that resembles class based inheritance in other object oriented languages. Classes are just special functions that can be declared to resembles classes in other languages. In JavaScript, we can have class declarations and class expressions, because they are just functions. So like all other functions, there are function declarations and function expressions. Classes serve a templates to create new objects.

Defining Classes

To declare a class, or make a class declaration, we use the class keyword to do so. For example, to declare a simple class, we can write:

class Person{
  constructor(firstName, lastName) {
    this.firstName= firstName;
    this.lastName = lastName;
  }
}

Class declarations aren’t hoisted so they can used before they are defined in the code, as the JavaScript interpreter will not automatically pull them up to the top. So the class above won’t work before it’s defined in the code like the following:

const person = new Person('John', 'Smith');
class Person{
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}

We will get a ReferenceError if we run the code above.

We can also define a class by a class expression, which is an alternative syntax for defining a class. They can be named or unnamed. We can also assign a class to a variable like we do with functions. If we do that, we can reference the class by its name. For example, we can define:

let Person = class {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}

To get the name of the unnamed classes above, we can get the name with the name property, like so:

console.log(Person.name);


We can also undefined a named class like the following:


let Person = class Person2{
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}

Then to get the name of the class, we can use the name property again. So we if we write:

console.log(Person.name)


we get Person2 logged.

The class body is defined with curly brackets. We define the class members inside the brackets. The body of the class is executed in strict mode, so everything defined in strict mode applies to the definition of a class, so we can’t define variables with out some keyword before it like var , let or const , and many other rules apply when you define a class. Classes in JavaScript also have a constructor method that lets us set fields when the object is instantiated with a class . Each class can only have one constructor method in it. If there’s more than one, then SyntaxError will be thrown. A constructor have to also call the super method to call the constructor of the super class inside if it the class extends a parent class.

Methods that aren’t declared static constitutes of the prototypical methods of the class. They are called after an object has been created by using the new keyword. For example, the following class have only prototypical methods:


class Person{
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  get fullName(){
    return `${this.firstName} ${this.lastName}`  
  }
  sayHi(){
    return `Hi, ${this.firstName} ${this.lastName}`
  }
}

In the Person class above, fullName and sayHi are prototypical methods. They are called like this:

const person = new Person('Jane', 'Smith');
person.fullName() // 'Jane Smith'

Static methods are methods that can be called without creating an object from the class using the new keyword. For instance, we can have something like the following:


class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
  sayHi() {
    return `Hi, ${this.firstName} ${this.lastName}`
  }
  static personCount() {
    return 3;
  }
}

We can call the personCount function without using the new keyword to create an instance of the class. So if we write:

Person.personCount

We get 3 returned.

The this value inside prototypical methods will be the value of the object. For static methods the value of this has the class that the static method is in as the value.

Getters and Setters

JavaScript classes can have getters and setter functions. Getters, as the name suggests, is a method that lets us get some data from a class. Setters are methods that gives us the ability to set some fields of the class. We denote getter functions with the get keyword and setters with the set keyword. For example, we can write a class that has getters and setters like the following:

class Person {
  constructor(firstName, lastName) {
    this._firstName = firstName;
    this._lastName = lastName;
  }
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
  get firstName() {
    return this._firstName
  }
  get lastName() {
    return this._lastName
  }
  sayHi() {
    return `Hi, ${this.firstName} ${this.lastName}`
  }
  set firstName(firstName) {
    this._firstName = firstName;
  }
  set lastName(lastName) {
    this._lastName = lastName;
  }
}

Then when we use the new keyword to construct a Person object, we can use them in the following way:


const person = new Person('Jane', 'Smith');
person.firstName = 'John';
person.lastName = 'Doe';
console.log(person.firstName, person.lastName)

Since we have the getter and setter functions, we can use them to set the data directly to set the data for firstName and lastName of the Person class. In the setter functions, which start with the keyword set , what we assign to them get passed into the parameters and set in the member of the class. In the getter functions, which are denote by get we return the member values so that we can use them.

JavaScript Inheritance

In JavaScript, we can create classes where the properties can be included in the properties of a child class.

So, we can have a high-level class that contains the properties that are common to all the child classes, and the child class can have its own special properties that are not in any other classes.

For example, if we have an Animal class with the common properties and methods, like name and the eat method, then the Bird class can just inherit the common properties in the Animal class. They don’t have to be defined in the Bird class again.

We can write the following to do inheritance in JavaScript:

class Animal {
  constructor(name) {
    this.name = name;
  }
  eat() {
    console.log('eat');
  }
}
class Bird extends Animal {
  constructor(name, numWings) {
    super(name);
    this.numWings = numWings;
  }
}
const bird = new Bird('Joe', 2);
console.log(bird.name)
bird.eat();

In the example above, we have the parent class, Animal, that has the eat method, which all classes that extends from Animal will have, so they don’t have to define eat again.

We have the Bird class which extends the Animal class. Note that in the constructor of the Bird class, we have the super() function call to call the parent’s class constructor to populate the properties of the parent class in addition to the properties of the child class.

Classes cannot extend regular objects, which cannot be constructed with the new keyword. If we want to inherit from a regular object, we have to use the Object.setPrototypeOf function to set a class to inherit from a regular object. For example:

const Animal = {
  eat() {
    console.log(`${this.name} eats`);
  }
};
class Cat{
  constructor(name) {
    this.name = name;
  }
}
class Chicken{
  constructor(name) {
    this.name = name;
  }
}
Object.setPrototypeOf(Cat.prototype, Animal);
Object.setPrototypeOf(Chicken.prototype, Animal);
let cat = new Cat('Bob');
let chicken = new Chicken('Joe');
cat.eat();
chicken.eat();

If we run the example code above, we have see Bob eats and Joe eats logged because we have inherited the eat function from the Animal object.

this Keyword

The this keyword allows us to access the current object’s properties inside an object, unless you’re using arrow functions.

As we can see from the above example, we can get the properties of the instance of the child and the parent class in the object.

Mixins

We can use mixins to do multiple inheritance in JavaScript. Mixins are templates for creating classes. We need mixins to do multiple inheritance because JavaScript classes can only inherit from one super class, so multiple inheritance isn’t possible.

For example, if we have a base class, we can define mixins to incorporate the members from multiple classes into one by composing the mixins by calling one and then pass the returned result into the next one as the argument, an so on, like so:

class Base {
  baseFn() {
    console.log('baseFn called');
  }
}
let classAMixin = Base => class extends Base {
  a() {
    console.log('classAMixin called');
  }
};
let classBMixin = Base => class extends Base {
  b() {
    console.log('classBMixin called');
  }
};
class Bar extends classAMixin(classBMixin(Base)) {}
const bar = new Bar();
bar.baseFn()
bar.a()
bar.b()

In the code above, we have the Base class which we pass into the classBMixin to get the b function into the Base class, then we call the classAMixin by passing in the result of classBMixin(Base) into the argument of the classAMixin to return the a function from classAMixin into the Base class and then return the whole class with all the functions from all the classes incorporated into one.

If we call all the functions above like we did by creating an instance of the Bar object and then call the baseFn , a and b functions, then we get:

baseFn called
classAMixin called
classBMixin called

This means that we have all the functions from the mixins incorporated into the new Bar class.

In JavaScript, classes are just syntactic sugar to make the prototypical inheritance of JavaScript clearer by letting us structure the code in a way that’s more like typical inheritance class based object oriented inheritance pattern. This means that we write classes to and use the new keyword to create objects from the classes, but underneath the syntactic sugar, we are still using prototypical inheritance to extend objects. We can extend classes from objects and we can also use mixins to do multiple inheritance in of JavaScript classes.