Skip to content

techteam92/Telegram-integration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TypeScript Concepts for Backend Development

This guide provides an in-depth exploration of key TypeScript concepts essential for backend developers, complete with examples, detailed explanations, and practical use cases. Use this as a reference for yourself and to train your team.


1. Type Annotations

TypeScript allows developers to define the types of variables, function parameters, and return values. This ensures type safety and helps catch errors early during development.

Example:

let message: string = "Hello, TypeScript!";
function add(a: number, b: number): number {
  return a + b;
}

const result = add(5, 10); // 15

Detailed Explanation:

  • message: string ensures that message can only contain string values. Attempting to assign another type will trigger a compile-time error.
  • add(a: number, b: number): number enforces that the arguments and return value are numbers, ensuring consistency and preventing unexpected behavior.

Real-world Use Case: Enforcing strict types in API request handlers ensures that incoming and outgoing data adhere to expected formats, reducing bugs in production systems.


2. Interfaces

Interfaces define the structure of an object. They ensure consistency by requiring objects to conform to a specific shape.

Example:

interface User {
  id: number;
  name: string;
  email: string;
}

function getUserInfo(user: User): string {
  return `User: ${user.name}, Email: ${user.email}`;
}

const user: User = { id: 1, name: "John", email: "[email protected]" };
console.log(getUserInfo(user));

Detailed Explanation:

  • The User interface specifies that any object of this type must have id, name, and email properties, each with specific types.
  • Passing an object that does not conform to the interface structure will result in a TypeScript error.

Real-world Use Case: Interfaces are widely used to define the structure of database models or to validate API request payloads.


3. Generics

Generics provide a way to create reusable and flexible components while maintaining type safety.

Example:

function getFirstElement<T>(items: T[]): T {
  return items[0];
}

const numbers = [1, 2, 3];
const strings = ["a", "b", "c"];

console.log(getFirstElement(numbers)); // 1
console.log(getFirstElement(strings)); // "a"

Detailed Explanation:

  • <T> represents a placeholder type that is specified when the function is called.
  • This allows getFirstElement to work with arrays of any type while preserving the type information.

Real-world Use Case: Use generics in repository patterns to handle CRUD operations for various database entities with type safety.


4. Classes and Constructors

Classes encapsulate data and behavior into a single structure. Constructors are used to initialize object properties when creating instances of a class.

Example:

class Product {
  name: string;
  price: number;

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

  getDetails(): string {
    return `${this.name} costs $${this.price}`;
  }
}

const product = new Product("Laptop", 1200);
console.log(product.getDetails());

Detailed Explanation:

  • The constructor initializes the name and price properties when creating an instance of Product.
  • Methods like getDetails define the behavior associated with the class.

Real-world Use Case: Define service classes for handling business logic or models that represent database entities.


5. Access Modifiers

Access modifiers (public, private, protected) control the visibility and accessibility of class members.

Example:

class User {
  private password: string;

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

  public getPassword(): string {
    return this.password;
  }
}

const user = new User("securePassword123");
console.log(user.getPassword()); // "securePassword123"

Detailed Explanation:

  • private restricts access to within the class only.
  • public makes methods or properties accessible from anywhere.

Real-world Use Case: Use access modifiers to encapsulate sensitive data like passwords or tokens and expose them only through secure methods.


6. Decorators

Decorators are special functions that can modify classes, methods, or properties. They are extensively used in frameworks like NestJS for dependency injection and middleware.

Example:

function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Method ${propertyKey} called with arguments:`, args);
    return originalMethod.apply(this, args);
  };
}

class Calculator {
  @LogMethod
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(5, 10); // Logs: "Method add called with arguments: [5, 10]"

Detailed Explanation:

  • @LogMethod is a method decorator that intercepts method calls to add logging functionality.
  • Decorators can be applied to classes, properties, methods, and parameters to implement cross-cutting concerns like logging, validation, or authentication.

Real-world Use Case: Use decorators in controllers to handle validation or middleware in frameworks like NestJS.


7. Dependency Injection (DI)

Dependency Injection is a design pattern where dependencies are provided externally rather than being instantiated within a class. This enhances modularity and testability.

Example:

class DatabaseService {
  connect() {
    console.log("Connected to database.");
  }
}

class UserService {
  constructor(private dbService: DatabaseService) {}

  getUserData() {
    this.dbService.connect();
    console.log("Fetching user data...");
  }
}

const dbService = new DatabaseService();
const userService = new UserService(dbService);
userService.getUserData();

Detailed Explanation:

  • Instead of creating a DatabaseService instance inside UserService, it is injected through the constructor.
  • This separation of concerns makes it easier to test UserService by injecting mocked dependencies.

Real-world Use Case: Manage services like database connections or logging in scalable backend systems using dependency injection frameworks like InversifyJS or the built-in DI system in NestJS.


About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 5