Get started with TypeScript today! 🆗
Tags: typescript, webdev, javascript, codenewbie
Published: 2020-10-30 16:54:40

#What & why ? 🧐#
[TypeScript](https://www.typescriptlang.org/) is an open-source language which builds on JavaScript. At the end of the day, TypeScript is no more than compiled JavaScript code and it runs everywhere.

Writing TypeScript code let you catch error during development and saves you a lot of time when debugging. It brings new features that considerably improve your code maintainability and if you are already familiar with JavaScript, there is a gentle learning curve.

#Setup 🔨#
In order to get started with TypeScript, you should install the compiler locally.

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

You can now create any .ts file you want and run the following command:

```bash
tsc app.ts
```

It should compile your app.ts file and create a new app.js file that contains "classic" JavaScript code.

TypeScript compiler is very flexible and lets you decide how it should behave. The first thing you have to do when starting a new project is to run this command:

```bash
tsc --init
```

Well done, you successfully created a tsconfig.json file that allows you to customize the compiler behavior.

Understanding the configuration file is a great way to improve your TypeScript skills, read the [official doc](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) if you want to dive deeper in.

#Core features ⭐️#

✅ Types
The main feature that comes from using TypeScript is type declaration. Most of JavaScript code running out there is un-typed and it is perfectly fine but if you are used to strongly typed programming languages, you may not like it so much.

TypeScript comes to the rescue, you are now able to explicitly tell the compiler what type of data your variables should have and what type of data a function returns.

```TypeScript
// app.js
let num;
num = 5;
num = "Five"; /* It works */

// app.ts
let num: Number;
num = 5;
num = "Five"; /* Type 'string' is not assignable to type 'Number' */
```

In this example, the compiler will complain if I accidentally assign a String to a variable that was supposed to be a Number. 

Here is a non-exhaustive list of types that TypeScript understands:

```TypeScript
// Primitives
const num: Number = 5;
const word: String = "Hello";
const bool: Boolean = true;

// Non-Primitives
const numArr: Array<Number> = [1, 2, 3];
const obj: Object = {};

// Tuples
const tuple: [String, Number, Number] = ["Hello", 1, 2]; // Fixed size and types array

// Unions
let union: Number | String = 5; // Allow multiples type possibilities
union = "World";

// Enums
enum Color { // Initialize numeric values with a name
    Red = 0,
    Blue = 1,
    Green = 42,
  }
const color = Color.Green;
console.log(color); // Displays 42

// Any
let something: any; // Any type

// Void
let nothing: void;
const returnNothing = (): void => console.log("Nothing"); // Return nothing

// Never
const error = (message: string): never => { // Always throw an exception
    throw new Error(message);
  }

// Custom 
type Name = "John" | "James";
let customName: Name;
customName = "John";
customName = "James";
customName = "Max"; // Type '"Max"' is not assignable to type 'name'
```

✅ Object-Oriented Programming

JavaScript already supports the object-oriented approach but with TypeScript, we take things to the next level!

If you are unfamiliar with classes, here is an example:

```TypeScript
// Class
class Pet {
    name: String;

    constructor(name: String) {
        this.name = name;
    }

    makeNoise = (): void => console.log(`${this.name} makes noise`);
}

// Inheritance
class Dog extends Pet {
    breed: String;

    constructor(name: String, breed: String) {
        super(name);
        this.breed = breed;
    }
}

const dog = new Dog("Max", "Akita");
dog.makeNoise(); // Displays: Max makes noise
```

So far, nothing really new. This works quite the same way with JavaScript.

Access modifiers are a thing in many others programming languages and thanks to TypeScript we can work with them as well.

```TypeScript
// Class
class Pet {
    public name: String; // Accessible everywhere
    private _age: Number; // Accessible from the class itself only
    protected isDog: Boolean; // Accessible from the class and its subclasses

    static petCount = 0; // Not accessible from instances of the class
    static readonly species = 'Canis Familaris'; // Cannot be modified

    constructor(name: String, age: Number, isDog: Boolean) {
        this.name = name;
        this._age = age;
        this.isDog = isDog;
    }

    makeNoise = (): void => console.log(`${this.name} makes noise`);
}

const pet = new Pet("Maw", 5, true);

console.log(pet.name); // Displays: "Max"
pet.name = "Rex";
console.log(pet.name); // Displays: "Rex"

console.log(pet._age); // Property 'age' is private and only accessible within class 'Pet'
console.log(pet.isDog); // Property 'isDog' is protected and only accessible within class 'Pet' and its subclasses.

console.log(Pet.petCount); // Displays: 0
console.log(Pet.species); // Displays: 'Canis Familaris'
```

In this dummy example, we manage the access to our class variables thanks to access modifiers. They prevent unwanted variables assignments from the outside.

A quick side note for the 'static' keyword. Static variables are available on the class itself and does not differ from one instance of this class to another.

Read more about static variables [here](https://techformist.com/static-variables-methods-typescript/).

Finally, let me introduce [interfaces](https://www.typescriptlang.org/docs/handbook/interfaces.html#our-first-interface)! Interfaces describe a set of attributes that an object should implement.

```TypeScript
interface iShape {
    draw: Function;
    width: number;
    height: number;
}

class Square implements iShape {
    width: number;
    height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }

    draw = () => console.log(`Drawing shape ${this.width * this.height}`);
    
}

class Circle implements iShape {} 
// Class 'Circle' incorrectly implements interface 'iShape'.Type 'Circle' is missing the following properties from type 'iShape': draw, width, height
```

Here is a potential use case, we want to make sure that our 'shape' variable has a width, height and a draw method:

```TypeScript
interface iShape {
    draw: Function;
    width: number;
    height: number;
}

class Square implements iShape {
    width: number;
    height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }

    draw = () => console.log(`Drawing shape ${this.width * this.height}`);
    
}

class UIElement {
    width: number;
    height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }
} 

const square = new Square(50, 50);
const image = new UIElement(100, 50);

let shape: iShape = square;
shape = image;
// Property 'draw' is missing in type 'UIElement' but required in type 'iShape'.
```

✅ Generics

Getting started with typed programming, you could get confused and write code like that:

```TypeScript
const numFun = (num: number): number => {
    return num;
}

const strFun = (str: string): string => {
    return str;
}
```
Of course, this would lead to a huge amount of work ...
One possible workaround is to work with the "Any" type.

```TypeScript
const anyFun = (arg: any): any => {
    return arg;
}
```

This works just fine, but we are losing the whole interest of working with TypeScript: type safety. 

Once again, TypeScript comes with a built-in solution to improve code reusability.

```TypeScript
const generic = <T>(arg: T): T => arg;
```

#Conclusion

TypeScript is a great tool to work with and has a lot to offer. I am only at the beginning of my journey and I already love it.

Let me know what you think of TypeScript and my article.

Thank you for reading! 😇