TypeScript Classes and Objects
Classes are the core concept of object-oriented programming (OOP), serving as blueprints for creating objects. TypeScript fully supports the class syntax introduced in ES6 and adds features like type annotations and access modifiers on top of it.
What are Classes and Objects?
- Class: A template or blueprint used to describe the common properties (data) and behaviors (methods) of a category of objects.
- Object: An instance of a class. Created using the
newkeyword, possessing the properties and methods defined by the class.
Defining a Class
Here's a simple class definition:
class Greeter {
// Property
greeting: string;
// Constructor
constructor(message: string) {
this.greeting = message;
}
// Method
greet() {
return "Hello, " + this.greeting;
}
}
// Create an instance of the class (an object)
let greeter = new Greeter("world");
console.log(greeter.greet()); // "Hello, world"Inheritance
Inheritance is a mechanism that allows one class (subclass) to acquire the properties and methods of another class (parent class). Use the extends keyword to implement inheritance.
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
// Snake is a subclass of Animal
class Snake extends Animal {
constructor(name: string) {
super(name); // Call the parent class constructor
}
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters); // Call the parent class method
}
}
let sam = new Snake("Sammy the Python");
sam.move();
// Slithering...
// Sammy the Python moved 5m.super(): In a subclass constructor, you must callsuper()to execute the parent class constructor.super.method(): Can be used to call overridden methods from the parent class.
Access Modifiers
TypeScript provides three access modifiers to control the accessibility of class members (properties and methods).
public(default): Members can be accessed anywhere. If you don't specify a modifier, it defaults topublic.private: Members can only be accessed within the class where they're declared. Neither subclasses nor class instances can access them.typescriptclass Person { private name: string; constructor(name: string) { this.name = name; } public greet() { console.log(`Hello, my name is ${this.name}`); } } let john = new Person("John"); john.greet(); // OK // console.log(john.name); // Error: Property 'name' is private.protected: Members can be accessed within the class where they're declared and in subclasses of that class, but not on class instances.typescriptclass Employee extends Person { private department: string; constructor(name: string, department: string) { super(name); this.department = department; } public getElevatorPitch() { // Can access protected members of parent class in subclass // return `Hello, my name is ${this.name} and I work in ${this.department}.`; // If name is protected, the above line is OK. If it's private, it will error. } }
Readonly Modifier (readonly)
The readonly keyword ensures that a property can only be initialized when declared or in the constructor, and cannot be modified afterward.
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor(theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
// dad.name = "Man with the 3-piece suit"; // Error! name is readonly.Static Properties and Methods (static)
Static members belong to the class itself, not to instances of the class. You can access them directly through the class name without creating an object.
class Grid {
static origin = { x: 0, y: 0 };
calculateDistanceFromOrigin(point: { x: number; y: number; }) {
let xDist = (point.x - Grid.origin.x);
let yDist = (point.y - Grid.origin.y);
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor(public scale: number) { }
}
console.log(Grid.origin); // { x: 0, y: 0 }
let grid1 = new Grid(1.0);Abstract Classes (abstract)
Abstract classes serve as base classes for other classes. They cannot be directly instantiated. Abstract classes can contain abstract methods, which have no concrete implementation and must be implemented in derived classes.
abstract class Department {
constructor(public name: string) {}
printName(): void {
console.log("Department name: " + this.name);
}
abstract printMeeting(): void; // Must be implemented in derived class
}
class AccountingDepartment extends Department {
constructor() {
super("Accounting and Auditing");
}
printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}
}
let department: Department; // Allowed to create a reference to an abstract type
// department = new Department(); // Error: Cannot create an instance of an abstract class
department = new AccountingDepartment(); // Allowed to instantiate and assign an abstract subclass
department.printName();
department.printMeeting();