TypeScript Classes
TypeScript adds types and access control to JavaScript classes.
A Typed Class
Declare each property with its type at the top of the class:
Example
class Student {
name: string;
marks: number;
constructor(name: string, marks: number) {
this.name = name;
this.marks = marks;
}
result(): string {
return this.marks >= 50 ? `${this.name} passed` : `${this.name} failed`;
}
}
const s = new Student("Ali", 72);
console.log(s.result());Ali passed
Access Modifiers
| Modifier | Who can use the member |
|---|---|
public | Everyone (this is the default) |
private | Only code inside this class |
protected | This class and classes that extend it |
readonly | Anyone can read it, nobody can change it after the constructor |
Example
class BankAccount {
readonly accountNo: string;
private balance: number = 0;
constructor(accountNo: string) {
this.accountNo = accountNo;
}
deposit(amount: number): void {
if (amount <= 0) throw new Error("Amount must be positive");
this.balance += amount;
}
getBalance(): number {
return this.balance;
}
}
const acc = new BankAccount("PK-0042");
acc.deposit(5000);
acc.deposit(2500);
console.log(acc.accountNo, acc.getBalance());
// acc.balance = 1000000; // Error: Property 'balance' is private
// acc.accountNo = "X"; // Error: Cannot assign to 'accountNo' because it is a read-only propertyPK-0042 7500
Making balance private means the only way to change it is through deposit(), which checks the amount. This idea is called encapsulation.
private is checked by TypeScript only. JavaScript also has its own private fields written with #, like #balance, which stay private even at runtime.
Parameter Properties
TypeScript has a shortcut: put a modifier on a constructor parameter, and it becomes a property automatically.
Example
class Product {
constructor(public name: string, private price: number) {}
priceWithTax(): number {
return Math.round(this.price * 1.17);
}
}
const fan = new Product("Pedestal Fan", 9000);
console.log(fan.name, fan.priceWithTax());Pedestal Fan 10530
Inheritance
extends creates a child class. super(...) calls the parent constructor. A child can override a method.
Example
class Employee {
constructor(public name: string, protected salary: number) {}
monthlyPay(): number {
return this.salary;
}
}
class Manager extends Employee {
constructor(name: string, salary: number, private bonus: number) {
super(name, salary);
}
override monthlyPay(): number {
return this.salary + this.bonus;
}
}
const team: Employee[] = [new Employee("Usman", 60000), new Manager("Hina", 90000, 15000)];
team.forEach(e => console.log(`${e.name}: Rs ${e.monthlyPay()}`));Usman: Rs 60000 Hina: Rs 105000
The Manager can read salary because it is protected.
Implementing an Interface
implements promises that a class has everything an interface describes. TypeScript checks the promise.
Example
interface Shape {
area(): number;
}
class Rectangle implements Shape {
constructor(private w: number, private h: number) {}
area(): number {
return this.w * this.h;
}
}
class Circle implements Shape {
constructor(private r: number) {}
area(): number {
return Math.round(Math.PI * this.r * this.r);
}
}
const shapes: Shape[] = [new Rectangle(4, 5), new Circle(3)];
console.log(shapes.map(sh => sh.area()));[ 20, 28 ]
Abstract Classes
An abstract class cannot be created with new. It is a base for other classes, and can force them to write certain methods:
Example
abstract class Notifier {
abstract send(msg: string): string;
}
class SmsNotifier extends Notifier {
send(msg: string): string {
return "SMS: " + msg;
}
}
console.log(new SmsNotifier().send("Your class starts at 5 PM"));SMS: Your class starts at 5 PM
Exercise
Exercise
A property marked private can be used from where?
