# Object Oriented Programming using Typescript: A Complete Guide

# Classes

They are the blueprint for its instances (objects that the class produce).

JavaScript has had classes since the ES5 language implementations. In there it was introduced to us the native implementations of “classes” was. Typescript extends the functionalities of that feature to make it look more like more common programming languages like Java for example.

Before we continue, if you're in a hurry, here's the GitHub [repository](https://github.com/henryjperez/ts_oop--tutorial) with all the code of this guide, just in case.

Now, let’s see what functionalities are and how to use them.

# Basic declaration

There is no mystery here. You use the keyword `class`, next to the name of the class (starting it with Uppercase by convention) and open brackets.

```typescript
/* ------------- Basic declaration ------------ */
class A {
	a1: string;
	a2: number;
	a3: boolean;

	constructor(a1: string, a2: number, a3: boolean) {
		this.a1 = a1;
		this.a2 = a2;
		this.a3 = a3;
	}
}
```

In that snippet of code, you have `a1` , `a2` and `a3` declared at the top of the class, that’s because Typescript will use that to tell `this` that those are part of its constructor and will not throw an error nor syntax warnings on the editor.

I know that’s a little too much boilerplate for just a simple class, but don’t worry, keep reading and I’ll show you a shorter way of doing that.

Then you can instantiate it like this:

```typescript
const aa = new A("New Class", 1, true);
console.log("Basic declaration:", aa);
```

## With methods

Went you wanna add methods, you don’t need to declare it at the top of the class nor do you have to use the keyword `function`.

```typescript
/* --------------- With methods --------------- */
class B {
	b1: string;
	b2: number;
	b3: boolean;

	constructor(b1: string, b2: number, b3: boolean) {
		this.b1 = b1;
		this.b2 = b2;
		this.b3 = b3;
	}

	run(time: "all day" | "just the mornings" | "anytime"): void {
		console.log(`I'm running ${time}, so you have this: ${this.b1} times ${this.b2} and it's ${this.b3}`);
	}
}
const bb = new B("Power", 59, true);
console.log("B class:", bb);
bb.run("all day");
```

# Encapsulation

Sometimes you’ll want to limit the kind of information that the **instances** share with the rest of the code, in those cases, you’ll use **encapsulation**.

The default way that classes instantiate their properties is `public`. Anyone can see them, anyone can change them, and anyone can manipulate that data.

Then, you have `private` properties which can only be manipulated by the class itself. By convention, you start the name of a **private** with an underscore `_` and they are strongly related to **getters** and **setters**, which I’ll explain in a moment

Some properties can only be read and cannot be modified, not even by the class itself, those are `readonly` .

And finally, we have `protected` which is very similar to **private** but with the difference that **protected** properties can also be modified by **inherited** classes (I’ll talk a little bit about that later).

```typescript
/* --------------- Encapsulation -------------- */
class C {
	c0: any // public by default
	public c1: null | number;
	private _c2: boolean | string;
	readonly c3: string;
	protected _c4: string;

	constructor({ c1, c2, c3, c4 }: { c1: null | number, c2: boolean, c3: string, c4: string, }) {
		this.c0 = "Whatever";
		this.c1 = c1;
		this._c2 = c2;
		this.c3 = c3;
		this._c4 = c4;
	}

	get c2() {
		return `Mr. C2 says that  it's value is: ${this._c2}. Now you can go, please`;
	}
	set c2(newValue: boolean | string) {
		// this.c3 = "Nope, still not changing"; // it will change the value, but the idea is to listen to typescript
		this._c2 = newValue;
	}

	set c4(newValue: string) {
		this._c4 = newValue;
	}

}
const cc = new C({ c1: null, c2: false, c3: "You can only see me, not modify me", c4: "Only the class can make me change and it's children" });
console.log("Encapsulation with class:", cc);

cc.c0 = "I'm public, whatever";
cc.c1 = 975;
// cc._c2 = true; // it will change the value, but the idea is to listen to typescript
cc.c2 = "VIP";
// cc.c3 = "Time to change... hahaha, not really"; // it will change the value, but the idea is to listen to typescript
// cc._c4 = "I told you, only the class can change me, not you"; // it will change the value, but the idea is to listen to typescript
cc.c4 = "Oh, well, if you say it please.... okey, let's go";

console.log("After changes:", cc)
console.log(cc.c2)
console.log(cc.c3)
// console.log(cc._c4) // it will display the value, but the idea is to listen to typescript
```

In the code above you’ll see a lot of comments, that’s because since this is an implementation of Typescript, many of these keywords don’t exist natively on Javascript, so the changes that you make in those scenarios are, even if they are invalid to Typescript, it will still run went it transpile to Javascript.

## Getters and Setters

Although this is not specific to Typescript but also Javascript. **Getters** and **Setters** are used to `set` or `get` a value of a property.

They are useful when you are using `private` or `protected` properties but you still want a way for the class to expose those values without directly referencing them.

Using the example above, they would like something like this:

```typescript
class C {
	private _c2: boolean | string;

	constructor({ c2, }: { c2: boolean }) {
		this._c2 = c2;
	}

	get c2() {
		return `Mr. C2 says that  it's value is: ${this._c2}. Now you can go, please`;
	}
	set c2(newValue: boolean | string) {
		// this.c3 = "Nope, still not changing"; // it will change the value, but the idea is to listen to typescript
		this._c2 = newValue;
	}

}
```

### Get

`get` will **return** the value of the **property.**

```typescript
console.log(cc.c2)
```

### Set

`set` can overwrite the value of the `private` **property.**

```typescript
cc.c2 = "VIP";
```

# Short constructor

To avoid all the boilerplate to declare the variables with their types at the beginning of the class, you can use **attributes** of the constructor to short that off. The only condition is to **add** the **access type** of **each** variable.

```typescript
/* ------------- Short constructor ------------ */
class D {
	constructor(
		// d0: any // you need to add the type of access: public, private, etc
		public d1: number,
		private d2: boolean,
		readonly d3: string,
		protected d4: number = 888,
	) { }

	d5(): void {
		console.log("Just logging");
	}
}
const dd = new D(13, true, "Reading...", /* 99 */);
console.log("Short constructor", dd);
```

# Inheritance

A class can have all the methods and properties that another class has. To do so, one class `extends` the functionalities of another, this process is called **inheritance** because, in some sense, the class **extended** will become a “parent” and the other a “child” that will inherit everything that its “parents” has.

As a side note, a class can only inherit one class at a time.

```typescript
/* ---------------- Inheritance --------------- */
class E {
	constructor(
		public e1: number,
		private e2: string = "Hi, I'm VIP",
		protected e3: string = "Hello, I'm can be used be the inheritance",
	) { }

	e4() {
		console.log("%c Here, just doing some Class E stuff", "color: pink; background-color: black",);
	}
}
class F extends E {
	constructor(
		e1: number, // for the super class don't put the access type (public, private, etc)
		public f1: number,
	) {
		super(e1);
	}

	f2() {
		console.log(`Super thing 1 ${this.e1}`);
		// console.log(`Super thing 2 ${this.e2}`); // privates can be extended to the children
		console.log(`Super thing 3 ${this.e3}`);

		super.e4();
	}
}

const ee = new E(2000);
const ff = new F(2501, 3000);
console.log(ee);
console.log(ff);
ff.f2();
// class G extends A, B, C, D, {} // it can only extend 1 class at the time
```

# Static methods

With the `static` keyword you can use properties and methods (mostly methods) without instantiating the class but with the **class** itself. Just keep in mind that the object instance `this` will not work as expected since there will be nothing instantiated yet.

```typescript
/* ------------------ Statics ----------------- */
class G {
	constructor(
		public gg = "Good game, gg",
	) { }

	static g = "gg, GG, gg";
	static ggGGgg() {
		console.log(`By the way, gg. ${this.gg}. Woops, I forgot that you need to initialize my first, unless... ${this.g}...`);
	}
}
G.ggGGgg();
console.log(G.g)
```

# Abstract Classes

An abstract class is the class you don’t want to instantiate because they are too open in its definition and too vague to make an object out of it. Instead, what you wanna do is to define it and let other classes inherit from it. That’s the whole point of an abstract class.

```typescript
/* ----------------- Abstract ----------------- */
// when a class is too general
// and you don't want to allow instances of that class
// but you still want to inherit
// then you can use an abstract class
interface ILiving {
	name: string;
	exists(): void;
}
abstract class LivingThing implements ILiving { // ignore the "interface" and "implements" for now
	constructor(
		public name: string = "perrito",
	) { }

	exists(): void {
		console.log("Existing");
	}
}

// const livingThing = new LivingThing("Creature"); // Just don't, ok?
class Dog extends LivingThing {
	constructor(
		name: string,
		public power: string,
	) {
		super(name);
	}

	move(): void {
		console.log("Moving using 4 legs");
	}
}
const dog = new Dog("Perrito", "Perfection");
console.log("Extending from abstract class", dog);
dog.exists();
dog.move();
```

# Interfaces in classes

Interfaces are related to objects and only exist on Typescript, not in Javascript. They declare what **properties** and **methods** the object will have and what **type** of data it’ll manage.

```typescript
interface H {
	h1: number;
	h2(): number;
}
```

Like classes, they can extend from each other. But, there is no such thing as **polymorphism,** which I’ll explain in another moment, but means that you can’t overwrite a property, for example `h1` with another interface.

```typescript
/* ---------------- Interfaces ---------------- */
interface H {
	h1: number;
	h2(): number;
}
interface I {
	i1: string;
	i2: ILiving;
}
interface J extends H, I {
	j1: boolean;
}
```

And you use the keyword `implements` to use them in your classes.

```typescript
class K implements H, I, J { // in this example implementing "H" and "I" are optionals since "J" already does that
	constructor(
		public h1: number,

		public i1: string,
		public i2: ILiving,

		public j1: boolean,
	) {}

	h2() {
		return 66;
	}
}
const kk = new K(44, "Welcome", dog, true);
console.log("Interfaces and classes =>", kk)
```

---

Well, there you have it. A complete guide to Object Oriented Programming using Typescript. If you have anything to add to it please comment on it or reach out to me through my social media:

[Twitter](https://twitter.com/henryjperez), [LinkedIn](https://www.linkedin.com/in/henryjperez/), [Instagram](https://www.instagram.com/henryjperez/), [Github](https://github.com/henryjperez/), [Medium](https://medium.com/@henryjperez) (For more opinion-based posts), and here on [Hashnode](https://hashnode.com/@henryjperez) and my [Hashnode blog](https://dev.henryjperez.com/). Also, follow me if you want XD

Remember that [here's the repository](https://github.com/henryjperez/ts_oop--tutorial) with all the code.

Have a nice day and until next time. Bye.
