Table of Contents Show
Object-oriented programming (OOP) is a programming paradigm that involves organizing code into objects that interact with each other.
TypeScript is an object-oriented programming language that builds on top of JavaScript, adding support for static typing and other features that make it easier to write and maintain large-scale applications.
Here are some of the key concepts of OOP in TypeScript:
Classes
Classes are used to define object blueprints, which encapsulate data and behavior. TypeScript classes can have properties, methods, and constructors.
class Person {
firstName: string;
lastName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName(): string {
return this.firstName + " " + this.lastName;
}
}
const person = new Person("John", "Doe");
console.log(person.getFullName()); // Output: "John Doe"
Inheritance
Inheritance allows classes to inherit properties and methods from other classes. TypeScript supports single and multiple inheritance using the extends
keyword.
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
}
}
const dog = new Dog();
dog.bark(); // Output: "Woof! Woof!"
dog.move(10); // Output: "Animal moved 10m."
Polymorphism
Polymorphism allows objects to take on multiple forms. In TypeScript, this is achieved through method overriding and method overloading.
class Shape {
area(): number {
return 0;
}
}
class Circle extends Shape {
radius: number;
constructor(radius: number) {
super();
this.radius = radius;
}
area(): number {
return Math.PI * this.radius * this.radius;
}
}
class Rectangle extends Shape {
width: number;
height: number;
constructor(width: number, height: number) {
super();
this.width = width;
this.height = height;
}
area(): number {
return this.width * this.height;
}
}
const shapes: Shape[] = [new Circle(5), new Rectangle(10, 20)];
for (const shape of shapes) {
console.log(shape.area());
}
Encapsulation
Encapsulation refers to the idea of hiding the implementation details of a class and exposing only the public interface. In TypeScript, this is achieved through the use of access modifiers such as public
, private
, and protected
.
class BankAccount {
private balance: number = 0;
deposit(amount: number) {
this.balance += amount;
}
withdraw(amount: number) {
if (this.balance >= amount) {
this.balance -= amount;
return true;
}
return false;
}
getBalance(): number {
return this.balance;
}
}
const account = new BankAccount();
account.deposit(100);
console.log(account.getBalance()); // Output: 100
account.withdraw(50);
console.log(account.getBalance()); // Output: 50
Implements versus Extends
In TypeScript, the implements
keyword is used to implement an interface, while the extends
keyword is used to create a subclass that inherits from a base class. Here’s a brief overview of the differences between these two keywords:
The implements
keyword is used to ensure that a class adheres to a particular interface. An interface is a way of defining a contract that specifies the properties and methods that a class must implement.
When a class implements an interface, it is required to implement all of the properties and methods specified in the interface.
interface Printable {
print(): void;
}
class Document implements Printable {
print() {
console.log("Printing document...");
}
}
const document = new Document();
document.print(); // Output: "Printing document..."
The extends
keyword is used to create a subclass that inherits from a base class. The subclass inherits all of the properties and methods of the base class, and can also define its own properties and methods.
class Animal {
move() {
console.log("Moving...");
}
}
class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
}
}
const dog = new Dog();
dog.move(); // Output: "Moving..."
dog.bark(); // Output: "Woof! Woof!"
It’s worth noting that a class can both implement an interface and extend a base class at the same time.
interface Printable {
print(): void;
}
class Document {
title: string;
constructor(title: string) {
this.title = title;
}
}
class PrintableDocument extends Document implements Printable {
print() {
console.log(`Printing document: ${this.title}`);
}
}
const document = new PrintableDocument("My Document");
document.print(); // Output: "Printing document: My Document"
Access modifiers: Public, Private, Protected, Static, Readonly
In TypeScript, access modifiers are used to control the visibility of class members. There are four access modifiers available in TypeScript: public
, private
, protected
, and readonly
.
In addition, TypeScript also supports static
members, which belong to the class rather than individual instances of the class.
The public
access modifier is the default and can be used to make class members accessible from anywhere, both within and outside the class.
class Person {
name: string;
}
const person = new Person();
person.name = "John";
console.log(person.name); // Output: "John"
The private
access modifier restricts access to class members to only within the class. Private members cannot be accessed from outside the class, including subclasses.
class BankAccount {
private balance: number;
constructor(balance: number) {
this.balance = balance;
}
deposit(amount: number) {
this.balance += amount;
}
getBalance(): number {
return this.balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // Output: 150
console.log(account.balance); // Compiler error: "Property 'balance' is private and only accessible within class 'BankAccount'."
The protected
access modifier restricts access to class members to within the class and its subclasses. Protected members can be accessed from subclasses, but not from outside the class hierarchy.
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log(`Woof! My name is ${this.name}`);
}
}
const dog = new Dog("Fido");
dog.bark(); // Output: "Woof! My name is Fido"
console.log(dog.name); // Compiler error: "Property 'name' is protected and only accessible within class 'Animal' and its subclasses."
The readonly
modifier indicates that a class member can only be set once, either during initialization or in the constructor.
class Person {
readonly name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person("John");
console.log(person.name); // Output: "John"
person.name = "Jane"; // Compiler error: "Cannot assign to 'name' because it is a read-only property."
The static
keyword is used to create class members that belong to the class itself rather than individual instances of the class. Static members can be accessed directly from the class, without creating an instance.
class MathUtils {
static PI: number = 3.14159;
static calculateCircumference(radius: number): number {
return 2 * this.PI * radius;
}
}
console.log(MathUtils.calculateCircumference(5)); // Output: 31.4159
console.log(MathUtils.PI); // Output: 3.14159
It’s worth noting that the readonly
and static
modifiers can be combined.
class Person {
static readonly defaultName: string = "John";
}
console.log(Person.defaultName); // Output: "John"
Person.defaultName = "Jane"; // Compiler error: "Cannot assign to 'defaultName' because it is a read-only property."
Final Words
In conclusion, TypeScript provides powerful features for implementing Object-Oriented Programming (OOP) concepts, such as classes, inheritance, and access modifiers.
These features help developers to create more robust, maintainable, and reusable code by encapsulating data and behavior within classes and controlling access to class members.
By using access modifiers like public, private, and protected, developers can enforce encapsulation and ensure that class members are used appropriately. Additionally, TypeScript’s support for static and readonly members provides more control over class behavior and member initialization.
Overall, TypeScript’s OOP features provide a solid foundation for building complex and scalable applications.