DEV Community

Cover image for Get started with TypeScript today! 🆗
Killian Frappart
Killian Frappart

Posted on • Edited on

Get started with TypeScript today! 🆗

What & why ? 🧐

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

npm install -g typescript
Enter fullscreen mode Exit fullscreen mode

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

tsc app.ts
Enter fullscreen mode Exit fullscreen mode

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:

tsc --init
Enter fullscreen mode Exit fullscreen mode

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

// 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' */
Enter fullscreen mode Exit fullscreen mode

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:

// 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'
Enter fullscreen mode Exit fullscreen mode

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

// 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
Enter fullscreen mode Exit fullscreen mode

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.

// 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'
Enter fullscreen mode Exit fullscreen mode

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.

Finally, let me introduce interfaces! Interfaces describe a set of attributes that an object should implement.

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
Enter fullscreen mode Exit fullscreen mode

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

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'.
Enter fullscreen mode Exit fullscreen mode

✅ Generics

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

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

const strFun = (str: string): string => {
    return str;
}
Enter fullscreen mode Exit fullscreen mode

Of course, this would lead to a huge amount of work ...
One possible workaround is to work with the "Any" type.

const anyFun = (arg: any): any => {
    return arg;
}
Enter fullscreen mode Exit fullscreen mode

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.

const generic = <T>(arg: T): T => arg;
Enter fullscreen mode Exit fullscreen mode

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! 😇

Top comments (0)