All you need to know about Typescript5 min read

What is Typescript?

In short, it’s a superset of Javascript! Nothing more or less.

That said, any Javascript code is valid Typescript.
On the other hand, Typescript needs to be transpiled to Javascript in order to work.
That means it has to be compiled (which I find it as it’s weakness, hence – slow workflow).

Nevertheless, Typescript, has some features which are currently lacking in Javascript, ie:

⦁ object oriented features
⦁ strong types
⦁ compile time errors

To use Typescript we need to install it like this:

npm install -g typescript

To check current Typescript version use:

tsc --version

To transpile your .js code, you need to write:

tsc your_script_filename.ts

Variables

If you want to know differences between variables in javascript check this tutorial about javascript variables.

Types

In Typescript there are several types we can use while coding:

let num: number;
let word: string;
let isValid: boolean;
let anything: any;
let wholeNumbers: number[] = [1,2,3,4,5];
let whatever: any[] = ['some string', 1, true, 'd'];

These are all pretty self explanatory types.

Though, when using enum type it’s much more convenient to write it in Typescript than Javascript.

For example, if you are to transpile enum type, you would get in Javascript something like this:

var Day;
(function (Day) {
    Day[Day["Monday"] = 0] = "Monday";
    Day[Day["Tuesday"] = 1] = "Tuesday";
    Day[Day["Wednesday"] = 2] = "Wednesday";
    Day[Day["Thursday"] = 3] = "Thursday";
    Day[Day["Friday"] = 4] = "Friday";
    Day[Day["Saturday"] = 5] = "Saturday";
    Day[Day["Sunday"] = 6] = "Sunday";
})(Day || (Day = {}));

Type (casting) assertions

There are two types of assertions, both are valid:

// Original syntax
var convertedType = < ConvertedType > typeToConvert;
// Newer additional syntax
var convertedType = typeToConvertas as ConvertedType;

Arrow functions

More about arrow functions read at my previous article.

Interfaces

As in any OOP language, interfaces behave the same way in Typescript, ie:

interface Person {
	name: string;
	old: number;
	someFunc: ()  => void;
} 

But the only caveat I find is the naming convention, since it’s lacking the ‘I’ when naming interface.
So for me, sometimes is confusing to distinguish class of an interface.

If your main background is in C#, I find this caveat strange and sometimes misleading.
But on the other hand, if your background is in Java, using this kind of style makes sense. ie:

interface Person { name: string, old: number }

class PersonImpl implements Person {name: string, old: number }

Classes

Same as any OOP language. Feel free to check more about classes here.

Constructor

As already stated for some of the above things, constructor behaves the same way as in any other OOP language. Only difference is the syntax, ie:

class Person {
	name: string;
	old: number;
	constructor(name: string, old:number) {
		this.name = name;
		this.old = old;
	}
	greet() {
		console.log(`Hello ${this.name}. You are ${this.old} years old!`);
	}
}

Instantiating an object looks like this:

let person = Person ('Denis', 37);

To make params optional, use ‘?’ operator. ie:

 class Person {
name: string;
old: number;
constructor(name?: string, old?:number) {
this.name = name;
this.old = old;
}
}

This way when creating a new object we don’t need to pass any value to constructor, ie:

let person = new Person(); // is valid

Access Modifiers

In TS we have 3 types of access modifiers:

⦁ public
⦁ private
⦁ protected

By default in TS all members are PUBLIC.
To define access modifiers we need to do someting like this:

class Person {
	private name: string; // will not be accessible(visible) when instantiated new object
	public old: number;
}
let person = new Person();
person.name = 'Denis'; // -- not accessible due to 'private' modifier
person.old = 37; // works fine as by default is public modifier

As seen above, using ‘public’ keyword is not necessary as it is redundant.
So there is no need to write more redundant code, only write ‘private’ or ‘protected’ when necessary.

Cool feature

Writing less code when using access modifiers is viable like this:

class Person {
	constructor(private name: string, private old:string){}
	greet() {
		console.log(`Hello ${this.name}. You are ${this.old} years old!`);
	}
}
let person = new Person('Denis', 37);
person.greet();

When writing this way, TS automatically generates ‘private’ (might also be a ‘public’ or ‘protected’) variables (in this case ‘name’ and ‘old’) which makes our code much cleaner.

If using ‘public’ for example:

class Person {
	constructor(public name?: string, public old?:number){}
	greet() {
		console.log(`Hello ${this.name}. You are ${this.old} years old!`);
	}
}
let person = new Person();
person.name = "Denis";
person.old = 37;
person.greet();

Properties

Again, as in any other OOP language we can use getters and setters, and these are needed especially if we use ‘private’ access modifiers ie:

class Person {
	constructor(private _name: string, private _old:string){}
	greet() {
		console.log(`Hello ${this._name}. You are ${this._old} years old!`);
	}
	get old() {
		return this._old;
	}
	set old(value){
		// we can add validation logic here for instance
		if(value>30){
			console.log('You are not that young anymore! :)');
		}
		this._old = value;
	}
}
let person = new Person('Denis', 37);
let yearsOld = person.old;
person.greet();

To explain further above example, why we used ‘_in front of variable names!?

In short, naming convention!

We used it, to be able to access ‘old’ property by naming convention.
If we didn’t use ‘_‘ in front of variable names, then our ‘public’ variable name should have been capitalized.
Which is not by naming convention correct.

Modules

And last, we put each interface, class in seperate, own, files.
That way we make our code better organized, easier to maintain and more extendable.
To create modules per interface or class we need to user ‘export‘ and ‘import‘ keywords so we code like this:

// stored in own person.ts file
export class Person {
	constructor(public name?: string, public old?:number){}
	greet() {
		console.log(`Hello ${this.name}. You are ${this.old} years old!`);
	}
}
// stored in own Logic.ts file
import { Person } from './person'
let person = new Person();
person.name = "Denis";
person.old = 37;
person.greet();

To learn more about modules, stay tuned as that’s my next topic.

Thnx for reading and I hope you learned something out of this article.

Leave a Reply

Your email address will not be published. Required fields are marked *