Understanding Object-Oriented Programming
Object-oriented programming (OOP) is a programming paradigm that organizes software design around objects rather than actions. It focuses on classes, objects, inheritance, encapsulation, and polymorphism to create modular and reusable code structures.
Classes and Objects
In TypeScript, classes serve as blueprints for creating objects. A class defines properties (attributes) and methods (behaviors) that its instances will possess.
class Feline {
speciesName: string;
lifeStage: number;
constructor(speciesName: string) {
this.speciesName = speciesName;
this.lifeStage = 3;
}
vocalize(): void {
console.log(`Meow, I'm ${this.speciesName}`);
}
}
const whiskers = new Feline("Whiskers");
console.log(whiskers); // Feline: { "speciesName": "Whiskers", "lifeStage": 3 }
whiskers.vocalize(); // "Meow, I'm Whiskers"
Inheritance
Inheritance allows classes to derive properties and methods from other classes, promoting code reuse and establishing hierarchical relationships.
class LivingCreature {
speciesName: string;
lifeStage: number;
constructor(speciesName: string) {
this.speciesName = speciesName;
this.lifeStage = 3;
}
communicate() {
console.log('...');
}
}
class Feline extends LivingCreature {
furColor: string;
constructor(speciesName: string, furColor: string) {
super(speciesName);
this.furColor = furColor;
}
}
Method Overriding
Subclasses can override parent class methods to provide specialized implementations.
class LivingCreature {
speciesName: string;
lifeStage: number;
move() {
console.log(`Parent class movement method!`);
}
}
class Canine extends LivingCreature {
bark() {
console.log(`${this.speciesName} is barking!`);
}
move() {
console.log(`Child class movement method overriding parent!`);
}
}
Abstract Classes
Abstract classes cannot be instantiated directly and often contain abstract methods that must be implemented by subclasses.
abstract class LivingCreature {
consume() {
console.log('consuming');
}
abstract rest(): void;
}
class Canine extends LivingCreature {
speciesName: string;
constructor(speciesName: string) {
super();
this.speciesName = speciesName;
}
rest() {
console.log('canine resting');
}
}
Encapsulation
Encapsulation bundles data and methods together while controlling access through access modifiers.
Acces Modifiers
TypeScript provides three access modifiers: public (default), protected, and private.
class Person {
private personalName: string;
constructor(personalName: string) {
this.personalName = personalName;
}
get name() {
return this.personalName;
}
set name(personalName: string) {
this.personalName = personalName;
}
}
const individual = new Person('John');
console.log(individual.name); // Access via getter
individual.name = 'Jane'; // Modify via setter
Static Members
Static properties and methods belong to the class rather than instances.
class MathUtils {
static PI = 3.1415926;
static add(value1: number, value2: number) {
return value1 + value2;
}
}
console.log(MathUtils.PI);
console.log(MathUtils.add(10, 20));
Polymorphism
Polymorphism enables objects of different types to be treated as objects of a common super type.
abstract class LivingCreature {
abstract rest(): void;
}
class Canine extends LivingCreature {
rest() {
console.log('canine resting');
}
}
class Feline extends LivingCreature {
rest() {
console.log('feline resting');
}
}
const dog = new Canine();
const cat = new Feline();
const creatures: LivingCreature[] = [dog, cat];
creatures.forEach(creature => {
creature.rest(); // Different implementations based on actual type
});
Method Chaining with This Type
Methods can return 'this' to enable fluent interface patterns.
class ProcessFlow {
initialStep() {
return this;
}
subsequentStep() {
return this;
}
}
class CustomFlow extends ProcessFlow {
customStep() {
return this;
}
}
new CustomFlow().customStep().initialStep().customStep().subsequentStep();