Advertisements

Understanding the Basics of a TypeScript Class

TypeScript, a superset of JavaScript, brings powerful features to object-oriented programming, including classes. A TypeScript class is a blueprint for creating objects, encapsulating data, and defining behaviors. In this section, we will explore the basic structure of a class, constructors, properties, and methods.

Declaring a TypeScript Class

To declare a class in TypeScript, we use the class keyword followed by the class name. Below is a simple example:

class Person {
    name: string;
    age: number;
    
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    greet(): string {
        return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
    }
}

Breakdown of the Class:

  • Properties (name and age): Define characteristics of the object.
  • Constructor: A special method used to initialize object properties.
  • Method (greet): Defines a behavior for the class.

Creating an Instance of a Class

To use a class, we need to create an instance:

const person1 = new Person("Alice", 25);
console.log(person1.greet());

This prints:

Hello, my name is Alice and I am 25 years old.

Key Features and Benefits of Using TypeScript Classes

TypeScript enhances JavaScript classes with strong typing, access modifiers, and object-oriented principles. Let’s explore some key features and benefits.

1. Strong Typing and Type Safety

One of the biggest advantages of TypeScript is type safety. Unlike JavaScript, TypeScript enforces data types at compile-time, reducing runtime errors.

class Car {
    brand: string;
    year: number;
    
    constructor(brand: string, year: number) {
        this.brand = brand;
        this.year = year;
    }
}

const myCar = new Car("Toyota", 2022);
// myCar.year = "2022"; // ❌ Error: Type 'string' is not assignable to type 'number'.

2. Access Modifiers (Encapsulation)

Encapsulation is the principle of restricting access to certain class members. TypeScript provides three access modifiers:

  • public: Accessible anywhere.
  • private: Accessible only within the class.
  • protected: Accessible within the class and subclasses.
class BankAccount {
    private balance: number;
    
    constructor(initialBalance: number) {
        this.balance = initialBalance;
    }

    deposit(amount: number): void {
        this.balance += amount;
    }

    getBalance(): number {
        return this.balance;
    }
}

const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
// account.balance = 2000; // ❌ Error: Property 'balance' is private.

3. Inheritance (Extending a Class)

TypeScript supports class inheritance, allowing you to create a new class based on an existing one.

class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    makeSound(): void {
        console.log("Some generic sound...");
    }
}

class Dog extends Animal {
    makeSound(): void {
        console.log("Woof woof!");
    }
}

const myDog = new Dog("Buddy");
myDog.makeSound(); // Woof woof!

4. Getters and Setters

Getters and setters allow controlled access to private properties.

class User {
    private _password: string;

    constructor(password: string) {
        this._password = password;
    }

    get password(): string {
        return "*****"; // Hide actual password
    }

    set password(newPassword: string) {
        if (newPassword.length < 6) {
            console.log("Password must be at least 6 characters long.");
        } else {
            this._password = newPassword;
        }
    }
}

const user = new User("secure123");
console.log(user.password); // *****
user.password = "123"; // Password must be at least 6 characters long.

5. Abstract Classes

Advertisements

Download the free ebook

Abstract classes define a base structure for other classes but cannot be instantiated directly.

abstract class Shape {
    abstract getArea(): number;
}

class Circle extends Shape {
    radius: number;
    constructor(radius: number) {
        super();
        this.radius = radius;
    }
    getArea(): number {
        return Math.PI * this.radius * this.radius;
    }
}

const myCircle = new Circle(5);
console.log(myCircle.getArea()); // 78.54

TypeScript classes provide a structured, type-safe way to implement object-oriented programming in JavaScript. By leveraging strong typing, encapsulation, inheritance, getters/setters, and abstract classes, developers can write scalable and maintainable applications. Understanding these fundamentals will help you build robust software solutions using TypeScript.

How to Create and Extend a TypeScript Class

TypeScript provides a robust way to work with object-oriented programming (OOP) concepts, including class creation and inheritance. In this section, we will explore how to create a class and extend it using inheritance.

Creating a TypeScript Class

To define a class in TypeScript, use the class keyword followed by a name. Below is a basic example:

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log("Some generic sound...");
    }
}

Key Elements:

  • Properties (name): Stores data for each object instance.
  • Constructor: Initializes properties when an instance is created.
  • Method (makeSound): Defines a behavior for the class.

Extending a Class

Inheritance allows one class to extend another, inheriting its properties and methods. Use the extends keyword:

class Dog extends Animal {
    breed: string;

    constructor(name: string, breed: string) {
        super(name);
        this.breed = breed;
    }

    makeSound(): void {
        console.log("Woof woof!");
    }
}

Explanation:

  • The Dog class inherits from Animal.
  • The super(name) call invokes the parent class constructor.
  • The makeSound method is overridden to provide a specific implementation.

Using the Extended Class

const myDog = new Dog("Buddy", "Golden Retriever");
console.log(myDog.name); // Buddy
console.log(myDog.breed); // Golden Retriever
myDog.makeSound(); // Woof woof!

Best Practices for Writing Clean and Scalable TypeScript Classes

Writing clean and scalable TypeScript classes ensures maintainability and efficiency. Follow these best practices to improve your code quality.

1. Use Access Modifiers

Access modifiers (public, private, protected) control visibility and enforce encapsulation.

class User {
    private password: string;

    constructor(password: string) {
        this.password = password;
    }
}
  • private: The property can only be accessed within the class.
  • protected: Accessible within the class and its subclasses.
  • public: Accessible from anywhere.

2. Implement Interfaces for Consistency

Interfaces help enforce a contract for classes, improving maintainability.

interface Vehicle {
    speed: number;
    drive(): void;
}

class Car implements Vehicle {
    speed: number;
    constructor(speed: number) {
        this.speed = speed;
    }
    drive(): void {
        console.log(`Driving at ${this.speed} mph`);
    }
}

3. Use Readonly Properties for Immutable Data

If a property should not be modified after initialization, use readonly.

class Config {
    readonly apiUrl: string = "https://api.example.com";
}

4. Leverage Getters and Setters

Control access to properties using getters and setters.

class Account {
    private _balance: number = 0;

    get balance(): number {
        return this._balance;
    }

    set balance(amount: number) {
        if (amount >= 0) {
            this._balance = amount;
        } else {
            console.log("Invalid amount");
        }
    }
}

5. Favor Composition Over Inheritance When Possible

Advertisements

Sometimes, composition is preferable to inheritance to reduce complexity.

class Engine {
    start(): void {
        console.log("Engine started");
    }
}

class Car {
    private engine = new Engine();
    startCar(): void {
        this.engine.start();
    }
}

6. Use Abstract Classes for Common Behaviors

Abstract classes define a template for subclasses.

abstract class Shape {
    abstract getArea(): number;
}

class Square extends Shape {
    constructor(private side: number) {
        super();
    }
    getArea(): number {
        return this.side * this.side;
    }
}

By following these practices, you can write clean, scalable, and maintainable TypeScript classes. Leveraging access modifiers, interfaces, getters/setters, composition, and abstraction ensures robust and efficient applications.

Conclusion

Effectively using TypeScript classes can significantly transform the way we develop modern applications. Starting with understanding the basics, it’s crucial to recognize how classes help us structure code in a more organized and readable manner. The key features and benefits of using TypeScript classes, such as static typing and inheritance, not only enhance code robustness but also facilitate collaboration within development teams.

By creating and extending classes, we can fully harness the power of object-oriented programming, making our code more reusable and scalable. Following best practices, such as keeping the code clean and adhering to SOLID design principles, ensures that our classes remain manageable and efficient, even as our projects grow in complexity.

Advertisements

Download the free ebook