Classes in TypeScript
Learn how to use Classes in TypeScript with this detailed tutorial. Includes basic and advanced examples to help you master Classes.
Introduction
Classes in TypeScript are a powerful way to create reusable components. They provide a means of creating objects with properties and methods, and they support inheritance, access modifiers, and much more.
Basic Examples
Here are some basic examples of using Classes in TypeScript:
Defining a Class
A basic example of defining a class in TypeScript.
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}
let greeter = new Greeter("world");
console.log(greeter.greet()); // Hello, world
Inheritance
Classes can extend other classes 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(); // Woof! Woof!
dog.move(10); // Animal moved 10m.
dog.bark(); // Woof! Woof!
Public, Private, and Protected Members
TypeScript provides three access modifiers: public
, private
, and protected
.
class Animal {
private name: string;
constructor(name: string) {
this.name = name;
}
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Bird extends Animal {
protected fly(distanceInMeters: number) {
console.log(`${this.name} flew ${distanceInMeters}m.`);
// Error: Property 'name' is private and only accessible within class 'Animal'.
}
}
const cat = new Animal("Cat");
cat.move(10); // Cat moved 10m.
Advanced Examples
Here are some advanced examples of using Classes in TypeScript:
Abstract Classes
Abstract classes are base classes from which other classes may be derived. They may not be instantiated directly.
abstract class Department {
constructor(public name: string) {}
printName(): void {
console.log("Department name: " + this.name);
}
abstract printMeeting(): void; // Must be implemented in derived classes
}
class AccountingDepartment extends Department {
constructor() {
super("Accounting and Auditing"); // constructors in derived classes must call super()
}
printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}
generateReports(): void {
console.log("Generating accounting reports...");
}
}
let department: Department; // ok to create a reference to an abstract type
// department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment();
department.printName();
department.printMeeting();
// department.generateReports(); // error: method doesn't exist on declared abstract type
Getters and Setters
You can use getters and setters to control access to the properties of a class.
class Employee {
private _fullName: string = "";
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (newName && newName.length > 0) {
this._fullName = newName;
} else {
console.log("Error: Please provide a valid name");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
console.log(employee.fullName); // Bob Smith
Static Properties and Methods
Static members are visible on the class itself rather than on the instances.
class Grid {
static origin = { x: 0, y: 0 };
calculateDistanceFromOrigin(point: { x: number; y: number }): number {
let xDist = point.x - Grid.origin.x;
let yDist = point.y - Grid.origin.y;
return Math.sqrt(xDist * xDist + yDist * yDist);
}
}
let grid = new Grid();
console.log(Grid.origin); // { x: 0, y: 0 }
Interfaces and Classes
A class can implement an interface.
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
Mixins
Mixins are a way to implement multiple inheritance.
class Disposable {
isDisposed: boolean = false;
dispose() {
this.isDisposed = true;
}
}
class Activatable {
isActive: boolean = false;
activate() {
this.isActive = true;
}
deactivate() {
this.isActive = false;
}
}
class SmartObject implements Disposable, Activatable {
isDisposed: boolean = false;
isActive: boolean = false;
dispose: () => void;
activate: () => void;
deactivate: () => void;
constructor() {
setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
}
}
applyMixins(SmartObject, [Disposable, Activatable]);
let smartObj = new SmartObject();
setTimeout(() => smartObj.activate(), 1000);
setTimeout(() => smartObj.deactivate(), 2000);
setTimeout(() => smartObj.dispose(), 3000);
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
});
});
}
Parameter Properties
Parameter properties let you create and initialize a member in one step.
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {}
}
let dad = new Octopus("Man with the 8 strong legs");
console.log(dad.name); // Man with the 8 strong legs
Class Expressions
Class expressions are another way to define classes.
let Greeter = class {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}
let greeterInstance = new Greeter("world");
console.log(greeterInstance.greet()); // Hello, world
This Parameter in Methods
You can explicitly indicate that a method does not use the class instance using this
.
class MyClass {
name = "MyClass";
getName = () => {
return this.name;
}
}
let c = new MyClass();
let g = c.getName;
console.log(g()); // MyClass
Conclusion
Classes in TypeScript provide a powerful way to create and manage reusable components. They offer a robust framework for inheritance, encapsulation, and abstraction. By using classes, you can write more organized, maintainable, and scalable code.