Welcome to The Coding College, where we make programming concepts easy to understand! At The Coding College, we are passionate about helping you improve your coding skills. In this post, we’ll explore TypeScript Classes, a key feature of object-oriented programming (OOP) in TypeScript.
What Are Classes in TypeScript?
A class in TypeScript is a blueprint for creating objects with shared properties and methods. It simplifies OOP concepts by introducing structure and type safety into JavaScript’s class system.
Why Use Classes in TypeScript?
- Encapsulation: Classes bundle data and behavior together.
- Reusability: Define reusable blueprints for objects.
- Inheritance: Extend functionality from one class to another.
- Type Safety: TypeScript adds static types to class properties and methods.
Declaring a Class
Basic Syntax
class ClassName {
propertyName: PropertyType;
constructor(parameterName: ParameterType) {
this.propertyName = parameterName;
}
methodName(): ReturnType {
// Method body
}
}
Example: A Simple Class
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
greet(): string {
return `Hello, my name is ${this.name}`;
}
}
const person = new Person("Alice");
console.log(person.greet()); // Output: Hello, my name is Alice
Access Modifiers
TypeScript classes support access modifiers to control the visibility of properties and methods:
public
(default): Accessible anywhere.private
: Accessible only within the class.protected
: Accessible within the class and subclasses.
Example: Using Access Modifiers
class Employee {
public name: string;
private salary: number;
constructor(name: string, salary: number) {
this.name = name;
this.salary = salary;
}
getSalary(): number {
return this.salary;
}
}
const employee = new Employee("Bob", 50000);
console.log(employee.name); // Output: Bob
// console.log(employee.salary); // Error: Property 'salary' is private
console.log(employee.getSalary()); // Output: 50000
Read-Only Properties
Properties can be marked as readonly
, making them immutable after initialization.
class Car {
readonly brand: string;
constructor(brand: string) {
this.brand = brand;
}
}
const car = new Car("Toyota");
console.log(car.brand); // Output: Toyota
// car.brand = "Honda"; // Error: Cannot assign to 'brand' because it is a read-only property
Getters and Setters
Use getters and setters to control access to class properties.
Example: Getters and Setters
class Circle {
private _radius: number;
constructor(radius: number) {
this._radius = radius;
}
get radius(): number {
return this._radius;
}
set radius(value: number) {
if (value > 0) {
this._radius = value;
} else {
throw new Error("Radius must be positive");
}
}
}
const circle = new Circle(5);
console.log(circle.radius); // Output: 5
circle.radius = 10;
console.log(circle.radius); // Output: 10
Inheritance
Classes can extend other classes to reuse and enhance functionality.
Example: Inheritance
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
move(): string {
return `${this.name} is moving`;
}
}
class Dog extends Animal {
bark(): string {
return `${this.name} says Woof!`;
}
}
const dog = new Dog("Buddy");
console.log(dog.move()); // Output: Buddy is moving
console.log(dog.bark()); // Output: Buddy says Woof!
Abstract Classes
An abstract class cannot be instantiated and serves as a base for other classes.
Example: Abstract Class
abstract class Shape {
abstract area(): number;
describe(): string {
return "This is a shape";
}
}
class Rectangle extends Shape {
width: number;
height: number;
constructor(width: number, height: number) {
super();
this.width = width;
this.height = height;
}
area(): number {
return this.width * this.height;
}
}
const rectangle = new Rectangle(10, 5);
console.log(rectangle.area()); // Output: 50
Static Properties and Methods
Static members belong to the class itself, not individual instances.
Example: Static Members
class MathUtils {
static pi: number = 3.14159;
static calculateCircumference(radius: number): number {
return 2 * MathUtils.pi * radius;
}
}
console.log(MathUtils.pi); // Output: 3.14159
console.log(MathUtils.calculateCircumference(5)); // Output: 31.4159
Implementing Interfaces
Classes can implement interfaces to enforce specific structures.
Example: Class Implementing an Interface
interface Printable {
print(): void;
}
class Document implements Printable {
content: string;
constructor(content: string) {
this.content = content;
}
print(): void {
console.log(this.content);
}
}
const doc = new Document("TypeScript Classes are powerful!");
doc.print(); // Output: TypeScript Classes are powerful!
Real-World Applications
- Reusable Components: Use classes to create reusable UI components in frameworks like Angular.
- Data Models: Define structured models for API data.
- Encapsulation: Hide implementation details and expose only what’s necessary.
Best Practices
- Encapsulate Logic: Use
private
andprotected
to enforce encapsulation. - Prefer Read-Only for Constants: Mark properties that shouldn’t change as
readonly
. - Keep Classes Small: Follow the Single Responsibility Principle (SRP).
- Use Abstract Classes for Base Behavior: Define common functionality in abstract classes.
- Document Classes and Methods: Write clear comments for better maintainability.
Common Pitfalls
- Overuse of Static Methods: Overusing static members can make code harder to test.
- Ignoring Access Modifiers: Always define access modifiers for clarity.
- Complex Inheritance Chains: Deep inheritance hierarchies can lead to rigid and error-prone designs.
Conclusion
Classes in TypeScript offer a robust way to structure and organize your code. With features like inheritance, encapsulation, and static typing, they enhance your ability to build scalable, maintainable applications.