Class Basics
// Basic class
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): string {
return `Hello, I'm ${this.name}`;
}
}
const person = new Person("Alice", 30);
console.log(person.greet());
// Parameter properties shorthand
class User {
constructor(
public name: string,
public email: string,
private password: string
) {}
}
// Equivalent to:
class UserVerbose {
public name: string;
public email: string;
private password: string;
constructor(name: string, email: string, password: string) {
this.name = name;
this.email = email;
this.password = password;
}
}
Access Modifiers
class BankAccount {
// public - accessible anywhere (default)
public accountHolder: string;
// private - only accessible within the class
private balance: number;
// protected - accessible in class and subclasses
protected accountNumber: string;
// readonly - can only be set in constructor
readonly createdAt: Date;
constructor(holder: string, initialBalance: number) {
this.accountHolder = holder;
this.balance = initialBalance;
this.accountNumber = this.generateAccountNumber();
this.createdAt = new Date();
}
private generateAccountNumber(): string {
return Math.random().toString(36).substring(2, 12);
}
public deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
}
}
public getBalance(): number {
return this.balance;
}
}
const account = new BankAccount("Alice", 1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
// account.balance; // Error: private
// account.accountNumber; // Error: protected
Inheritance
class Animal {
constructor(public name: string) {}
move(distance: number = 0): void {
console.log(`${this.name} moved ${distance} meters`);
}
speak(): void {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // Call parent constructor
}
// Override parent method
speak(): void {
console.log(`${this.name} barks!`);
}
// New method
fetch(): void {
console.log(`${this.name} fetches the ball`);
}
}
class Cat extends Animal {
speak(): void {
super.speak(); // Call parent method
console.log(`${this.name} meows!`);
}
}
const dog = new Dog("Max", "Labrador");
dog.speak(); // "Max barks!"
dog.move(10); // "Max moved 10 meters"
dog.fetch(); // "Max fetches the ball"
Abstract Classes
// Abstract class - cannot be instantiated directly
abstract class Shape {
constructor(public color: string) {}
// Abstract method - must be implemented by subclasses
abstract getArea(): number;
abstract getPerimeter(): number;
// Concrete method - shared implementation
describe(): string {
return `A ${this.color} shape with area ${this.getArea()}`;
}
}
class Circle extends Shape {
constructor(color: string, public radius: number) {
super(color);
}
getArea(): number {
return Math.PI * this.radius ** 2;
}
getPerimeter(): number {
return 2 * Math.PI * this.radius;
}
}
class Rectangle extends Shape {
constructor(
color: string,
public width: number,
public height: number
) {
super(color);
}
getArea(): number {
return this.width * this.height;
}
getPerimeter(): number {
return 2 * (this.width + this.height);
}
}
// const shape = new Shape("red"); // Error: cannot instantiate abstract class
const circle = new Circle("red", 5);
const rectangle = new Rectangle("blue", 4, 6);
console.log(circle.describe());
console.log(rectangle.getArea());
Implementing Interfaces
interface Printable {
print(): void;
}
interface Saveable {
save(): Promise<void>;
load(): Promise<void>;
}
// Implement single interface
class Document implements Printable {
constructor(public content: string) {}
print(): void {
console.log(this.content);
}
}
// Implement multiple interfaces
class CloudDocument implements Printable, Saveable {
constructor(public content: string, private id: string) {}
print(): void {
console.log(this.content);
}
async save(): Promise<void> {
console.log(`Saving document ${this.id}`);
}
async load(): Promise<void> {
console.log(`Loading document ${this.id}`);
}
}
// Interface with class constraint
interface Repository<T> {
findById(id: string): Promise<T | null>;
save(item: T): Promise<void>;
delete(id: string): Promise<void>;
}
class UserRepository implements Repository<User> {
async findById(id: string): Promise<User | null> {
return null;
}
async save(user: User): Promise<void> {}
async delete(id: string): Promise<void> {}
}
Static Members
class MathUtils {
// Static property
static readonly PI = 3.14159;
// Private static property
private static instance: MathUtils | null = null;
// Static method
static add(a: number, b: number): number {
return a + b;
}
static multiply(a: number, b: number): number {
return a * b;
}
// Singleton pattern
static getInstance(): MathUtils {
if (!MathUtils.instance) {
MathUtils.instance = new MathUtils();
}
return MathUtils.instance;
}
// Static block (ES2022)
static {
console.log("MathUtils class initialized");
}
}
// Usage - no need to instantiate
console.log(MathUtils.PI);
console.log(MathUtils.add(2, 3));
console.log(MathUtils.multiply(4, 5));
Getters and Setters
class Temperature {
private _celsius: number = 0;
// Getter
get celsius(): number {
return this._celsius;
}
// Setter with validation
set celsius(value: number) {
if (value < -273.15) {
throw new Error("Temperature below absolute zero!");
}
this._celsius = value;
}
// Computed property
get fahrenheit(): number {
return (this._celsius * 9) / 5 + 32;
}
set fahrenheit(value: number) {
this._celsius = ((value - 32) * 5) / 9;
}
get kelvin(): number {
return this._celsius + 273.15;
}
}
const temp = new Temperature();
temp.celsius = 25;
console.log(temp.fahrenheit); // 77
console.log(temp.kelvin); // 298.15
temp.fahrenheit = 100;
console.log(temp.celsius); // 37.78
Key Takeaways
- • Use access modifiers: public, private, protected, readonly
- • Parameter properties shorthand in constructors
- • Abstract classes define contracts for subclasses
- • Classes can implement multiple interfaces
- • Static members belong to the class, not instances
- • Getters/setters provide controlled property access